1 /*
   2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 /*
   7  * Copyright (c) 1997, 1998, 1999
   8  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
   9  *
  10  * Redistribution and use in source and binary forms, with or without
  11  * modification, are permitted provided that the following conditions
  12  * are met:
  13  * 1. Redistributions of source code must retain the above copyright
  14  *    notice, this list of conditions and the following disclaimer.
  15  * 2. Redistributions in binary form must reproduce the above copyright
  16  *    notice, this list of conditions and the following disclaimer in the
  17  *    documentation and/or other materials provided with the distribution.
  18  * 3. All advertising materials mentioning features or use of this software
  19  *    must display the following acknowledgement:
  20  *      This product includes software developed by Bill Paul.
  21  * 4. Neither the name of the author nor the names of any co-contributors
  22  *    may be used to endorse or promote products derived from this software
  23  *    without specific prior written permission.
  24  *
  25  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
  26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
  29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  35  * THE POSSIBILITY OF SUCH DAMAGE.
  36  */
  37 
  38 #include <sys/conf.h>
  39 #include <sys/ddi.h>
  40 #include <sys/sunddi.h>
  41 #include <sys/dlpi.h>
  42 #include <sys/ethernet.h>
  43 #include <sys/strsubr.h>
  44 #include <sys/strsun.h>
  45 #include <sys/stat.h>
  46 #include <sys/byteorder.h>
  47 #include <sys/pccard.h>
  48 #include <sys/pci.h>
  49 #include <sys/policy.h>
  50 #include <sys/mac_provider.h>
  51 #include <sys/stream.h>
  52 #include <inet/common.h>
  53 #include <inet/nd.h>
  54 #include <inet/mi.h>
  55 
  56 #include "pcan.h"
  57 #include <sys/mac_wifi.h>
  58 #include <inet/wifi_ioctl.h>
  59 
  60 #ifdef  DEBUG
  61 #define PCAN_DBG_BASIC          0x1
  62 #define PCAN_DBG_INFO           0x2
  63 #define PCAN_DBG_SEND           0x4
  64 #define PCAN_DBG_RCV            0x8
  65 #define PCAN_DBG_LINKINFO       0x10
  66 #define PCAN_DBG_FW_VERSION     0x20
  67 #define PCAN_DBG_CMD            0x40
  68 uint32_t pcan_debug = 0;
  69 #define PCANDBG(x) \
  70         if (pcan_debug & PCAN_DBG_BASIC) cmn_err x
  71 #else
  72 #define PCANDBG(x)
  73 #endif
  74 
  75 static ddi_device_acc_attr_t accattr = {
  76                 DDI_DEVICE_ATTR_V0,
  77                 DDI_STRUCTURE_LE_ACC,
  78                 DDI_STRICTORDER_ACC,
  79 };
  80 
  81 static ddi_dma_attr_t control_cmd_dma_attr = {
  82         DMA_ATTR_V0,            /* version of this structure */
  83         0,                      /* lowest usable address */
  84         0xffffffffffffffffull,  /* highest usable address */
  85         0xffffffffull,          /* maximum DMAable byte count */
  86         4,                      /* alignment in bytes */
  87         0xfff,                  /* burst sizes (any) */
  88         1,                      /* minimum transfer */
  89         0xffffull,              /* maximum transfer */
  90         0xffffffffffffffffull,  /* maximum segment length */
  91         1,                      /* maximum number of segments */
  92         1,                      /* granularity */
  93         0,                      /* flags (reserved) */
  94 };
  95 
  96 void *pcan_soft_state_p = NULL;
  97 static int pcan_device_type;
  98 
  99 /*
 100  * brussels
 101  */
 102 static int      pcan_m_setprop(void *arg, const char *pr_name,
 103     mac_prop_id_t wldp_pr_num, uint_t wldp_length,
 104     const void *wldp_buf);
 105 static int      pcan_m_getprop(void *arg, const char *pr_name,
 106     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
 107 static void     pcan_m_propinfo(void *arg, const char *pr_name,
 108     mac_prop_id_t wldp_pr_num, mac_prop_info_handle_t mph);
 109 
 110 mac_callbacks_t pcan_m_callbacks = {
 111         MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
 112         pcan_gstat,
 113         pcan_start,
 114         pcan_stop,
 115         pcan_prom,
 116         pcan_sdmulti,
 117         pcan_saddr,
 118         pcan_tx,
 119         NULL,
 120         pcan_ioctl,
 121         NULL,
 122         NULL,
 123         NULL,
 124         pcan_m_setprop,
 125         pcan_m_getprop,
 126         pcan_m_propinfo
 127 };
 128 
 129 static char *pcan_name_str = "pcan";
 130 
 131 #ifdef  __sparc
 132 #define pcan_quiesce    ddi_quiesce_not_supported
 133 #else
 134 static int pcan_quiesce(dev_info_t *);
 135 #endif
 136 
 137 DDI_DEFINE_STREAM_OPS(pcan_dev_ops, nulldev, pcan_probe, pcan_attach,
 138     pcan_detach, nodev, NULL, D_MP, NULL, pcan_quiesce);
 139 
 140 extern struct mod_ops mod_driverops;
 141 static struct modldrv modldrv = {
 142         &mod_driverops,
 143         "Cisco-Aironet 802.11b driver",
 144         &pcan_dev_ops
 145 };
 146 
 147 static struct modlinkage modlinkage = {
 148         MODREV_1, (void *)&modldrv, NULL
 149         };
 150 
 151 int
 152 _init(void)
 153 {
 154         int stat;
 155 
 156         /* Allocate soft state */
 157         if ((stat = ddi_soft_state_init(&pcan_soft_state_p,
 158             sizeof (pcan_maci_t), 2)) != DDI_SUCCESS)
 159                 return (stat);
 160 
 161         mac_init_ops(&pcan_dev_ops, "pcan");
 162         stat = mod_install(&modlinkage);
 163         if (stat != 0) {
 164                 mac_fini_ops(&pcan_dev_ops);
 165                 ddi_soft_state_fini(&pcan_soft_state_p);
 166         }
 167 
 168         return (stat);
 169 }
 170 
 171 int
 172 _fini(void)
 173 {
 174         int stat;
 175 
 176         stat = mod_remove(&modlinkage);
 177         if (stat != DDI_SUCCESS)
 178                 return (stat);
 179         mac_fini_ops(&pcan_dev_ops);
 180         ddi_soft_state_fini(&pcan_soft_state_p);
 181         return (stat);
 182 }
 183 
 184 int
 185 _info(struct modinfo *modinfop)
 186 {
 187         return (mod_info(&modlinkage, modinfop));
 188 }
 189 
 190 static int
 191 pcan_probe(dev_info_t *dip)
 192 {
 193         int len, ret;
 194         char *buf;
 195         dev_info_t *pdip = ddi_get_parent(dip);
 196 
 197         PCANDBG((CE_NOTE, "pcan probe: parent dip=0x%p-%s(%d)\n", (void *)pdip,
 198             ddi_driver_name(pdip), ddi_get_instance(pdip)));
 199 
 200         ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type",
 201             (caddr_t)&buf, &len);
 202         if (ret != DDI_SUCCESS)
 203                 return (DDI_PROBE_FAILURE);
 204 
 205         PCANDBG((CE_NOTE, "pcan probe: device_type %s\n", buf));
 206         if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) {
 207                 pcan_device_type = PCAN_DEVICE_PCCARD;
 208 #ifdef DEBUG
 209                 if (pcan_debug & PCAN_DBG_FW_VERSION) {
 210                         cmn_err(CE_NOTE, "Cisco 802.11 pccard\n");
 211                 }
 212 #endif
 213                 ret = DDI_PROBE_SUCCESS;
 214         } else if (strcmp(buf, "pci") == 0) {
 215                 pcan_device_type = PCAN_DEVICE_PCI;
 216 #ifdef DEBUG
 217                 if (pcan_debug & PCAN_DBG_FW_VERSION) {
 218                         cmn_err(CE_NOTE, "Cisco 802.11 minipci card\n");
 219                 }
 220 #endif
 221                 ret = DDI_PROBE_SUCCESS;
 222         } else {
 223                 cmn_err(CE_NOTE, "pcan probe: unsupported card\n");
 224                 ret = DDI_PROBE_FAILURE;
 225         }
 226 
 227         kmem_free(buf, len);
 228         return (ret);
 229 }
 230 
 231 static int
 232 pcan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 233 {
 234         int ret;
 235         int instance;
 236         uint16_t stat;
 237         uint32_t err;
 238         pcan_maci_t *pcan_p;
 239         wifi_data_t     wd = { 0 };
 240         mac_register_t  *macp;
 241         modify_config_t cfgmod;
 242         char strbuf[256];
 243 
 244         PCANDBG((CE_NOTE, "dip=0x%p cmd=%x\n", (void *)dip, cmd));
 245         if (cmd != DDI_ATTACH)
 246                 goto attach_fail1;
 247 
 248         /*
 249          * Since this driver is porting from freebsd, so just like
 250          * the original driver, the minipci card doesn't work on amd64
 251          * machine.
 252          * For sparc, since no pci card is available for the test, so this
 253          * version doesn't support sparc. If there is card available and
 254          * requirement, future version will try to support sparc.
 255          * This driver works well for minipci card on 32bit x86
 256          * machine, so keep the code to just support minipci card on 32bit
 257          * mode.
 258          */
 259 #if defined(sparc) || defined(__sparc)
 260         if (pcan_device_type == PCAN_DEVICE_PCI) {
 261                 cmn_err(CE_NOTE, "pcan attach: this driver does not support "
 262                     "PCI/MiniPCI card on Sparc\n");
 263                 goto attach_fail1;
 264         }
 265 #endif /* sparc */
 266 #if defined(__amd64)
 267         if (pcan_device_type == PCAN_DEVICE_PCI) {
 268                 cmn_err(CE_NOTE, "pcan attach: this driver does not support "
 269                     "PCI/MiniPCI card on amd64\n");
 270                 goto attach_fail1;
 271         }
 272 #endif /* amd64 */
 273 
 274         /* Allocate soft state associated with this instance. */
 275         if (ddi_soft_state_zalloc(pcan_soft_state_p,
 276             ddi_get_instance(dip)) != DDI_SUCCESS) {
 277                 cmn_err(CE_CONT, "pcan attach: alloc softstate failed\n");
 278                 goto attach_fail1;
 279         }
 280         pcan_p = (pcan_maci_t *)ddi_get_soft_state(pcan_soft_state_p,
 281             ddi_get_instance(dip));
 282 
 283         pcan_p->pcan_device_type = pcan_device_type;
 284         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
 285                 if (ddi_regs_map_setup(dip, 0,
 286                     (caddr_t *)&pcan_p->pcan_cfg_base, 0, 0,
 287                     &accattr, &pcan_p->pcan_cfg_handle) != DDI_SUCCESS)
 288                         goto attach_fail2;
 289 
 290                 stat = ddi_get16(pcan_p->pcan_cfg_handle,
 291                     (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM));
 292                 stat |= (PCI_COMM_IO | PCI_COMM_MAE);
 293                 ddi_put16(pcan_p->pcan_cfg_handle,
 294                     (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM), stat);
 295 
 296                 ddi_regs_map_free(&pcan_p->pcan_cfg_handle);
 297                 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcan_p->pcan_bar0,
 298                     0, 0, &accattr, &pcan_p->pcan_handle0) != DDI_SUCCESS)
 299                         goto attach_fail3;
 300                 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&pcan_p->pcan_bar1,
 301                     0, 0, &accattr, &pcan_p->pcan_handle1) != DDI_SUCCESS)
 302                         goto attach_fail3;
 303                 if (ddi_regs_map_setup(dip, 3, (caddr_t *)&pcan_p->pcan_bar2,
 304                     0, 0, &accattr, &pcan_p->pcan_handle2) != DDI_SUCCESS)
 305                         goto attach_fail3;
 306         }
 307 
 308         pcan_p->pcan_dip             = dip;
 309         pcan_p->pcan_flag            = 0;
 310         pcan_p->glds_nocarrier               = 0;
 311         pcan_p->glds_noxmtbuf                = 0;
 312         pcan_p->glds_norcvbuf                = 0;
 313         pcan_p->pcan_socket          = ddi_getprop(DDI_DEV_T_NONE, dip,
 314             DDI_PROP_DONTPASS, "socket", -1);
 315 
 316         pcan_p->pcan_reschedule_need = B_FALSE;
 317         pcan_p->pcan_info_softint_pending = 0;
 318         pcan_p->pcan_reset_delay = ddi_getprop(DDI_DEV_T_ANY, dip,
 319             DDI_PROP_DONTPASS, "reset-delay", 5000);
 320 
 321         if (ddi_get_iblock_cookie(dip,
 322             0, &pcan_p->pcan_ib_cookie) != DDI_SUCCESS) {
 323                 cmn_err(CE_WARN, "pcan attach: get_iblk_cookie failed\n");
 324                 goto attach_fail3;
 325         }
 326 
 327         mutex_init(&pcan_p->pcan_glock, NULL,
 328             MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
 329         mutex_init(&pcan_p->pcan_scanlist_lock, NULL,
 330             MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
 331         mutex_init(&pcan_p->pcan_txring.an_tx_lock, NULL,
 332             MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
 333 
 334         if (ret = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
 335             &pcan_p->pcan_info_softint_id, &pcan_p->pcan_ib_cookie, NULL,
 336             pcan_info_softint, (caddr_t)pcan_p)) {
 337                 cmn_err(CE_WARN, "pcan attach: add info_softintr failed\n");
 338                 goto attach_fail3a;
 339         }
 340 
 341         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
 342                 if (ret = ddi_add_intr(dip, 0, NULL, NULL,
 343                     pcan_intr, (caddr_t)pcan_p)) {
 344                         cmn_err(CE_WARN, "pcan attach: add intr failed\n");
 345                         goto attach_fail4;
 346                 }
 347         } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
 348                 if (ret = pcan_register_cs(dip, pcan_p)) {
 349                         PCANDBG((CE_NOTE, "pcan attach: register_cs failed"
 350                             " %x\n", ret));
 351                         goto attach_fail4;
 352                 }
 353         } else {
 354                 cmn_err(CE_WARN, "pcan attach: unsupported device type\n");
 355                 goto attach_fail4;
 356         }
 357 
 358         mutex_enter(&pcan_p->pcan_glock);
 359         pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
 360         /* leaves IF down, intr disabled */
 361 
 362         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
 363                 if (ret = pcan_init_dma(dip, pcan_p)) {
 364                         cmn_err(CE_WARN, "pcan init_dma: failed\n");
 365                         mutex_exit(&pcan_p->pcan_glock);
 366                         goto attach_fail5;
 367                 }
 368         }
 369         if (ret = pcan_get_cap(pcan_p)) { /* sets macaddr for gld_register */
 370                 cmn_err(CE_WARN, "pcan attach: get_cap failed %x\n", ret);
 371                 mutex_exit(&pcan_p->pcan_glock);
 372                 goto attach_fail6;
 373         }
 374 
 375         mutex_exit(&pcan_p->pcan_glock);
 376         /*
 377          * Provide initial settings for the WiFi plugin; whenever this
 378          * information changes, we need to call mac_pdata_update()
 379          */
 380         wd.wd_secalloc = WIFI_SEC_NONE;
 381         wd.wd_opmode = IEEE80211_M_STA;
 382 
 383         macp = mac_alloc(MAC_VERSION);
 384         if (macp == NULL) {
 385                 PCANDBG((CE_NOTE, "pcan attach: "
 386                     "MAC version mismatch\n"));
 387                 goto attach_fail6;
 388         }
 389 
 390         macp->m_type_ident   = MAC_PLUGIN_IDENT_WIFI;
 391         macp->m_driver               = pcan_p;
 392         macp->m_dip          = dip;
 393         macp->m_src_addr     = pcan_p->pcan_mac_addr;
 394         macp->m_callbacks    = &pcan_m_callbacks;
 395         macp->m_min_sdu              = 0;
 396         macp->m_max_sdu              = IEEE80211_MTU;
 397         macp->m_pdata                = &wd;
 398         macp->m_pdata_size   = sizeof (wd);
 399 
 400         err = mac_register(macp, &pcan_p->pcan_mh);
 401         mac_free(macp);
 402         if (err != 0) {
 403                 PCANDBG((CE_NOTE, "pcan attach: "
 404                     "mac_register err\n"));
 405                 goto attach_fail6;
 406         }
 407 
 408         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
 409                 /* turn on CS interrupt */
 410                 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
 411                     CONF_IRQ_CHANGE_VALID;
 412                 cfgmod.Vpp1 = 50;
 413                 cfgmod.Vpp2 = 50;
 414                 (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
 415 
 416                 mutex_enter(&pcan_p->pcan_glock);
 417                 if (ret = pcan_init_nicmem(pcan_p)) {
 418                         cmn_err(CE_WARN, "pcan attach: init_nicmem failed %x\n",
 419                             ret);
 420                         mutex_exit(&pcan_p->pcan_glock);
 421                         goto attach_fail7;
 422                 }
 423                 mutex_exit(&pcan_p->pcan_glock);
 424         }
 425         (void) ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
 426             "bad-rids", (caddr_t)&pcan_p->pcan_badrids,
 427             &pcan_p->pcan_badrids_len);
 428 
 429         pcan_p->an_config.an_rxmode = AN_NORMAL_RXMODE;
 430         ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
 431         mutex_enter(&pcan_p->pcan_glock);
 432         list_create(&pcan_p->an_scan_list, sizeof (an_scan_list_t),
 433             offsetof(an_scan_list_t, an_scan_node));
 434         pcan_p->an_scan_num = 0;
 435         mutex_exit(&pcan_p->pcan_glock);
 436         pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
 437             pcan_p, drv_usectohz(1000000));
 438 
 439         instance = ddi_get_instance(dip);
 440         (void) snprintf(strbuf, sizeof (strbuf), "pcan%d", instance);
 441         if (ddi_create_minor_node(dip, strbuf, S_IFCHR,
 442             instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) {
 443                 goto attach_fail8;
 444         }
 445         mutex_enter(&pcan_p->pcan_glock);
 446         PCAN_DISABLE_INTR_CLEAR(pcan_p);
 447         (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
 448         pcan_p->pcan_flag |= PCAN_ATTACHED;
 449         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
 450                 pcan_p->pcan_flag |= PCAN_CARD_READY;
 451         }
 452         mutex_exit(&pcan_p->pcan_glock);
 453         return (DDI_SUCCESS);
 454 attach_fail8:
 455         if (pcan_p->an_scanlist_timeout_id != 0) {
 456                 (void) untimeout(pcan_p->an_scanlist_timeout_id);
 457                 pcan_p->an_scanlist_timeout_id = 0;
 458         }
 459         list_destroy(&pcan_p->an_scan_list);
 460 attach_fail7:
 461         (void) mac_unregister(pcan_p->pcan_mh);
 462 attach_fail6:
 463         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI)
 464                 pcan_free_dma(pcan_p);
 465 attach_fail5:
 466         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
 467                 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
 468         } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
 469                 pcan_unregister_cs(pcan_p);
 470         }
 471 attach_fail4:
 472         if (pcan_p->pcan_info_softint_id)
 473                 ddi_remove_softintr(pcan_p->pcan_info_softint_id);
 474 attach_fail3a:
 475         pcan_destroy_locks(pcan_p);
 476 attach_fail3:
 477         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
 478                 if (pcan_p->pcan_handle0)
 479                         ddi_regs_map_free(&pcan_p->pcan_handle0);
 480                 if (pcan_p->pcan_handle1)
 481                         ddi_regs_map_free(&pcan_p->pcan_handle1);
 482                 if (pcan_p->pcan_handle2)
 483                         ddi_regs_map_free(&pcan_p->pcan_handle2);
 484         }
 485 attach_fail2:
 486         ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
 487 attach_fail1:
 488         return (DDI_FAILURE);
 489 }
 490 
 491 static int
 492 pcan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 493 {
 494         pcan_maci_t *pcan_p;
 495         an_scan_list_t *scan_item0;
 496         int ret;
 497         pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip));
 498 
 499         if (cmd != DDI_DETACH)
 500                 return (DDI_FAILURE);
 501         if (!(pcan_p->pcan_flag & PCAN_ATTACHED))
 502                 return (DDI_FAILURE);
 503 
 504         ret = mac_disable(pcan_p->pcan_mh);
 505         if (ret != 0)
 506                 return (DDI_FAILURE);
 507 
 508         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
 509                 mutex_enter(&pcan_p->pcan_glock);
 510                 pcan_stop_locked(pcan_p);
 511                 PCAN_DISABLE_INTR(pcan_p);
 512                 mutex_exit(&pcan_p->pcan_glock);
 513         }
 514         if (pcan_p->an_scanlist_timeout_id != 0) {
 515                 (void) untimeout(pcan_p->an_scanlist_timeout_id);
 516                 pcan_p->an_scanlist_timeout_id = 0;
 517         }
 518         if (pcan_p->pcan_connect_timeout_id != 0) {
 519                 (void) untimeout(pcan_p->pcan_connect_timeout_id);
 520                 pcan_p->pcan_connect_timeout_id = 0;
 521         }
 522         mutex_enter(&pcan_p->pcan_scanlist_lock);
 523         scan_item0 = list_head(&pcan_p->an_scan_list);
 524         while (scan_item0) {
 525                 pcan_delete_scan_item(pcan_p, scan_item0);
 526                 scan_item0 = list_head(&pcan_p->an_scan_list);
 527         }
 528         list_destroy(&pcan_p->an_scan_list);
 529         mutex_exit(&pcan_p->pcan_scanlist_lock);
 530 
 531         (void) mac_unregister(pcan_p->pcan_mh);
 532 
 533         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
 534                 mutex_enter(&pcan_p->pcan_glock);
 535                 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
 536                 pcan_free_dma(pcan_p);
 537                 if (pcan_p->pcan_handle0)
 538                         ddi_regs_map_free(&pcan_p->pcan_handle0);
 539                 if (pcan_p->pcan_handle1)
 540                         ddi_regs_map_free(&pcan_p->pcan_handle1);
 541                 if (pcan_p->pcan_handle2)
 542                         ddi_regs_map_free(&pcan_p->pcan_handle2);
 543                 mutex_exit(&pcan_p->pcan_glock);
 544         } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
 545                 pcan_unregister_cs(pcan_p);
 546         } else {
 547                 cmn_err(CE_WARN, "pcan detach: unsupported device type\n");
 548         }
 549         pcan_destroy_locks(pcan_p);
 550         if (pcan_p->pcan_info_softint_id)
 551                 ddi_remove_softintr(pcan_p->pcan_info_softint_id);
 552 
 553         if (pcan_p->pcan_badrids_len)
 554                 kmem_free(pcan_p->pcan_badrids, pcan_p->pcan_badrids_len);
 555 
 556         ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
 557         ddi_remove_minor_node(dip, NULL);
 558 
 559         return (DDI_SUCCESS);
 560 }
 561 
 562 /*
 563  * card services and event handlers
 564  */
 565 
 566 static int
 567 pcan_register_cs(dev_info_t *dip, pcan_maci_t *pcan_p)
 568 {
 569         int ret;
 570         client_reg_t cr;
 571         client_handle_t chdl; /* uint encoding of socket, function, client */
 572         get_status_t card_status;
 573         request_socket_mask_t sock_req;
 574 
 575         bzero(&cr, sizeof (cr));
 576         cr.Attributes   = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE;
 577         cr.EventMask    = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
 578             CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP |
 579             CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | CS_EVENT_PM_SUSPEND |
 580             CS_EVENT_CLIENT_INFO;
 581         cr.event_callback_args.client_data = pcan_p;
 582         cr.Version = CS_VERSION;
 583         cr.event_handler = (csfunction_t *)pcan_ev_hdlr;
 584         cr.dip = dip;
 585         (void) strcpy(cr.driver_name, pcan_name_str);
 586         if (ret = csx_RegisterClient(&chdl, &cr)) {
 587                 cmn_err(CE_WARN, "pcan: RegisterClient failed %x", ret);
 588                 goto regcs_ret;
 589         }
 590 
 591         pcan_p->pcan_chdl = chdl;
 592 
 593         bzero(&card_status, sizeof (card_status));
 594         (void) csx_GetStatus(chdl, &card_status);
 595         PCANDBG((CE_NOTE, "pcan: getstat Sock=%x CState=%x SState=%x rState=%x",
 596             card_status.Socket, card_status.CardState,
 597             card_status.SocketState, card_status.raw_CardState));
 598         if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) {
 599                 /* card is not present, why are we attaching ? */
 600                 ret = CS_NO_CARD;
 601                 goto unreg;
 602         }
 603         cv_init(&pcan_p->pcan_cscv, NULL, CV_DRIVER, NULL);
 604         mutex_init(&pcan_p->pcan_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie);
 605         mutex_enter(&pcan_p->pcan_cslock);
 606         if (ret = csx_MapLogSocket(chdl, &pcan_p->pcan_log_sock)) {
 607                 cmn_err(CE_WARN, "pcan: MapLogSocket failed %x", ret);
 608                 goto fail;
 609         }
 610         PCANDBG((CE_NOTE, "pcan: logsock: LogSock=%x PhyAdapter=%x PhySock=%x",
 611             pcan_p->pcan_log_sock.LogSocket,
 612             pcan_p->pcan_log_sock.PhyAdapter,
 613             pcan_p->pcan_log_sock.PhySocket));
 614 
 615         /* turn on initialization events */
 616         sock_req.Socket = 0;
 617         sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
 618             CS_EVENT_REGISTRATION_COMPLETE;
 619         if (ret = csx_RequestSocketMask(chdl, &sock_req)) {
 620                 cmn_err(CE_WARN, "pcan: RequestSocketMask failed %x\n", ret);
 621                 goto fail;
 622         }
 623 
 624         /* wait for and process card insertion events */
 625         while (!(pcan_p->pcan_flag & PCAN_CARD_READY))
 626                 cv_wait(&pcan_p->pcan_cscv, &pcan_p->pcan_cslock);
 627         mutex_exit(&pcan_p->pcan_cslock);
 628 
 629         pcan_p->pcan_flag |= PCAN_CS_REGISTERED;
 630         return (CS_SUCCESS);
 631 fail:
 632         mutex_destroy(&pcan_p->pcan_cslock);
 633         cv_destroy(&pcan_p->pcan_cscv);
 634 unreg:
 635         (void) csx_DeregisterClient(chdl);
 636 regcs_ret:
 637         pcan_p->pcan_flag &= ~PCAN_CS_REGISTERED;
 638         return (ret);
 639 }
 640 
 641 static void
 642 pcan_unregister_cs(pcan_maci_t *pcan_p)
 643 {
 644         int ret;
 645         release_socket_mask_t mask;
 646         mask.Socket = pcan_p->pcan_socket;
 647 
 648         /*
 649          * The card service not registered means register_cs function
 650          * doesnot return TRUE. Then all the lelated resource has been
 651          * released in register_cs.
 652          */
 653         if (!(pcan_p->pcan_flag | PCAN_CS_REGISTERED))
 654                 return;
 655         (void) csx_ReleaseSocketMask(pcan_p->pcan_chdl, &mask);
 656 
 657         if (pcan_p->pcan_flag & PCAN_CARD_READY) {
 658                 pcan_card_remove(pcan_p);
 659         }
 660         mutex_destroy(&pcan_p->pcan_cslock);
 661         cv_destroy(&pcan_p->pcan_cscv);
 662         if (ret = csx_DeregisterClient(pcan_p->pcan_chdl))
 663                 cmn_err(CE_WARN, "pcan: deregister failed %x\n", ret);
 664 }
 665 static void
 666 pcan_destroy_locks(pcan_maci_t *pcan_p)
 667 {
 668         mutex_destroy(&pcan_p->pcan_txring.an_tx_lock);
 669         mutex_destroy(&pcan_p->pcan_scanlist_lock);
 670         mutex_destroy(&pcan_p->pcan_glock);
 671 }
 672 
 673 static int
 674 pcan_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
 675 {
 676         int ret = CS_SUCCESS;
 677         pcan_maci_t *pcan_p = (pcan_maci_t *)arg->client_data;
 678         client_info_t *ci_p = (client_info_t *)&arg->client_info;
 679 
 680         mutex_enter(&pcan_p->pcan_cslock);
 681         switch (event) {
 682         case CS_EVENT_CARD_INSERTION:
 683                 ret = pcan_card_insert(pcan_p);
 684                 cv_broadcast(&pcan_p->pcan_cscv);
 685                 break;
 686         case CS_EVENT_REGISTRATION_COMPLETE:
 687                 cv_broadcast(&pcan_p->pcan_cscv);
 688                 break;
 689         case CS_EVENT_CARD_REMOVAL:
 690                 if (priority & CS_EVENT_PRI_HIGH)
 691                         break;
 692                 pcan_card_remove(pcan_p);
 693                 cv_broadcast(&pcan_p->pcan_cscv);
 694                 break;
 695         case CS_EVENT_CLIENT_INFO:
 696                 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) !=
 697                     CS_CLIENT_INFO_SUBSVC_CS)
 698                         break;
 699 
 700                 ci_p->Revision = 0x0101;
 701                 ci_p->CSLevel = CS_VERSION;
 702                 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14);
 703                 (void) strcpy(ci_p->ClientName, PCAN_IDENT_STRING);
 704                 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
 705                 ci_p->Attributes |= CS_CLIENT_INFO_VALID;
 706                 break;
 707         case CS_EVENT_PM_SUSPEND:
 708                 pcan_do_suspend(pcan_p);
 709                 break;
 710         default:
 711                 ret = CS_UNSUPPORTED_EVENT;
 712                 break;
 713         }
 714         mutex_exit(&pcan_p->pcan_cslock);
 715         return (ret);
 716 }
 717 
 718 static int
 719 pcan_card_insert(pcan_maci_t *pcan_p)
 720 {
 721         int ret, hi, lo;
 722         tuple_t tuple;
 723         cisparse_t cisparse;
 724         io_req_t        io;
 725         irq_req_t       irq;
 726         config_req_t    cfg;
 727         cistpl_config_t config;
 728         cistpl_cftable_entry_t *tbl_p;
 729         register client_handle_t chdl = pcan_p->pcan_chdl;
 730         modify_config_t cfgmod;
 731 
 732         bzero(&tuple, sizeof (tuple));
 733         tuple.DesiredTuple = CISTPL_MANFID;
 734         if (ret = csx_GetFirstTuple(chdl, &tuple)) {
 735                 cmn_err(CE_WARN, "pcan: get manufacture id failed %x\n", ret);
 736                 goto insert_ret;
 737         }
 738         bzero(&cisparse, sizeof (cisparse));
 739         if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) {
 740                 cmn_err(CE_WARN, "pcan: parse manufacture id failed %x\n", ret);
 741                 goto insert_ret;
 742         }
 743         /* verify manufacture ID */
 744         PCANDBG((CE_NOTE, "pcan: manufacturer_id=%x card=%x\n",
 745             cisparse.manfid.manf, cisparse.manfid.card));
 746 
 747         bzero(&tuple, sizeof (tuple));
 748         tuple.DesiredTuple = CISTPL_FUNCID;
 749         if (ret = csx_GetFirstTuple(chdl, &tuple)) {
 750                 cmn_err(CE_WARN, "pcan: get function id failed %x\n", ret);
 751                 goto insert_ret;
 752         }
 753         bzero(&cisparse, sizeof (cisparse));
 754         if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) {
 755                 cmn_err(CE_WARN, "pcan: parse function id failed %x\n", ret);
 756                 goto insert_ret;
 757         }
 758         /* verify function ID */
 759         PCANDBG((CE_NOTE, "funcid=%x\n", cisparse.funcid.function));
 760 
 761         bzero(&tuple, sizeof (tuple));
 762         tuple.DesiredTuple = CISTPL_CONFIG;
 763         if (ret = csx_GetFirstTuple(chdl, &tuple)) {
 764                 cmn_err(CE_WARN, "pcan: get config failed %x\n", ret);
 765                 goto insert_ret;
 766         }
 767         bzero(&config, sizeof (config));
 768         if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) {
 769                 cmn_err(CE_WARN, "pcan: parse config failed %x\n", ret);
 770                 goto insert_ret;
 771         }
 772         PCANDBG((CE_NOTE,
 773             "pcan: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n",
 774             config.present, config.nr, config.hr, config.regs[0],
 775             config.base, config.last));
 776 
 777         hi = 0;
 778         lo = (int)-1;           /* really big number */
 779         tbl_p = &cisparse.cftable;
 780         tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 781         for (tbl_p->index = 0; tbl_p->index <= config.hr; ) {
 782                 PCANDBG((CE_NOTE, "pcan: tuple idx=%x:\n", tbl_p->index));
 783                 if (ret = csx_GetNextTuple(chdl, &tuple)) {
 784                         cmn_err(CE_WARN, "pcan: get cftable failed %x\n", ret);
 785                         break;
 786                 }
 787                 bzero((caddr_t)&cisparse, sizeof (cisparse));
 788                 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) {
 789                         cmn_err(CE_WARN, "pcan: parse cftable failed%x\n", ret);
 790                         break;
 791                 }
 792                 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR &&
 793                     tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
 794                         if (tbl_p->pd.pd_vcc.avgI > hi) {
 795                                 hi = tbl_p->pd.pd_vcc.avgI;
 796                                 pcan_p->pcan_config_hi = tbl_p->index;
 797                         }
 798                         if (tbl_p->pd.pd_vcc.avgI < lo) {
 799                                 lo = tbl_p->pd.pd_vcc.avgI;
 800                                 pcan_p->pcan_config = tbl_p->index;
 801                         }
 802                 }
 803                 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) {
 804                         if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC)
 805                                 pcan_p->pcan_vcc = tbl_p->pd.pd_vcc.nomV;
 806                         if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO)
 807                                 pcan_p->pcan_iodecode = tbl_p->io.addr_lines;
 808                 }
 809         }
 810         PCANDBG((CE_NOTE, "pcan: cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n",
 811             pcan_p->pcan_config_hi, pcan_p->pcan_config,
 812             pcan_p->pcan_vcc, pcan_p->pcan_iodecode));
 813 
 814         bzero(&io, sizeof (io));
 815         io.BasePort1.base = 0;
 816         io.NumPorts1 = 1 << pcan_p->pcan_iodecode;
 817         io.Attributes1 = IO_DATA_PATH_WIDTH_16;
 818         io.IOAddrLines = pcan_p->pcan_iodecode;
 819         if (ret = csx_RequestIO(chdl, &io)) {
 820                 cmn_err(CE_WARN, "pcan: RequestIO failed %x\n", ret);
 821                 goto insert_ret;
 822         }
 823         pcan_p->pcan_port = io.BasePort1.handle;
 824 
 825         if (ret = ddi_add_softintr(DIP(pcan_p), DDI_SOFTINT_HIGH,
 826             &pcan_p->pcan_softint_id, &pcan_p->pcan_ib_cookie, NULL,
 827             pcan_intr, (caddr_t)pcan_p)) {
 828                 cmn_err(CE_NOTE, "pcan: Add softintr failed\n");
 829                 goto insert_ret;
 830         }
 831         irq.Attributes = IRQ_TYPE_EXCLUSIVE;
 832         irq.irq_handler = ddi_intr_hilevel(DIP(pcan_p), 0) ?
 833             (csfunction_t *)pcan_intr_hi : (csfunction_t *)pcan_intr;
 834         irq.irq_handler_arg = pcan_p;
 835         if (ret = csx_RequestIRQ(chdl, &irq)) {
 836                 cmn_err(CE_WARN, "pcan: RequestIRQ failed %x\n", ret);
 837                 goto un_io;
 838         }
 839 
 840         bzero(&cfg, sizeof (cfg));
 841         cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */
 842         cfg.Vcc = 50; /* pcan_vcc == 0 */
 843         cfg.Vpp1 = 50;
 844         cfg.Vpp2 = 50;
 845         cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO;
 846         cfg.ConfigBase = config.base;
 847         cfg.ConfigIndex = pcan_p->pcan_config;
 848         cfg.Status = CCSR_IO_IS_8; /* no use */
 849         cfg.Present = config.present;
 850         pcan_p->pcan_flag |= PCAN_CARD_READY;
 851         if (ret = csx_RequestConfiguration(chdl, &cfg)) {
 852                 cmn_err(CE_WARN, "pcan: RequestConfiguration failed %x\n", ret);
 853                 goto un_irq;
 854         }
 855 
 856         if (pcan_p->pcan_flag & PCAN_SUSPENDED) {
 857                 mutex_enter(&pcan_p->pcan_glock);
 858                 pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
 859                 /* turn on CS interrupt */
 860                 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
 861                     CONF_IRQ_CHANGE_VALID;
 862                 cfgmod.Vpp1 = 50;
 863                 cfgmod.Vpp2 = 50;
 864                 (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
 865 
 866                 if (ret = pcan_init_nicmem(pcan_p)) {
 867                         cmn_err(CE_WARN, "pcan insert: init_nicmem failed %x\n",
 868                             ret);
 869                 }
 870                 PCAN_DISABLE_INTR_CLEAR(pcan_p);
 871                 ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
 872                 PCANDBG((CE_NOTE, "pcan insert set cmd ret =%x\n", ret));
 873                 pcan_p->pcan_flag &= ~PCAN_SUSPENDED;
 874                 mutex_exit(&pcan_p->pcan_glock);
 875         }
 876 
 877         if (pcan_p->pcan_flag & PCAN_PLUMBED) {
 878                 (void) pcan_start(pcan_p);
 879                 pcan_p->pcan_flag &= ~PCAN_PLUMBED;
 880                 PCANDBG((CE_NOTE, "pcan insert: active interrupt\n"));
 881         }
 882         return (CS_SUCCESS);
 883 un_irq:
 884         (void) csx_ReleaseIRQ(chdl, &irq);
 885 un_io:
 886         ddi_remove_softintr(pcan_p->pcan_softint_id);
 887 
 888         (void) csx_ReleaseIO(chdl, &io);
 889         pcan_p->pcan_port = 0;
 890 insert_ret:
 891         pcan_p->pcan_flag &= ~PCAN_CARD_READY;
 892         return (ret);
 893 }
 894 
 895 /*
 896  * assume card is already removed, don't touch the hardware
 897  */
 898 static void
 899 pcan_do_suspend(pcan_maci_t *pcan_p)
 900 {
 901         int ret;
 902         if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
 903                 if (pcan_p->pcan_connect_timeout_id != 0) {
 904                         (void) untimeout(pcan_p->pcan_connect_timeout_id);
 905                         pcan_p->pcan_connect_timeout_id = 0;
 906                 }
 907                 mutex_enter(&pcan_p->pcan_glock);
 908                 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
 909                 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
 910                         PCANDBG((CE_NOTE, "pcan: disable failed, ret %d\n",
 911                             ret));
 912                 if (ret = pcan_loaddef(pcan_p))
 913                         PCANDBG((CE_NOTE, "pcan: loaddef failed, ret %d\n",
 914                             ret));
 915                 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
 916                 mutex_exit(&pcan_p->pcan_glock);
 917         }
 918         pcan_p->pcan_flag |= PCAN_SUSPENDED;
 919 }
 920 
 921 
 922 /*
 923  * assume card is already removed, don't touch the hardware
 924  */
 925 static void
 926 pcan_card_remove(pcan_maci_t *pcan_p)
 927 {
 928         int ret;
 929         io_req_t io;
 930         irq_req_t irq;
 931 
 932         if (!(pcan_p->pcan_flag & PCAN_CARD_READY))
 933                 return;
 934         if (pcan_p->pcan_connect_timeout_id != 0) {
 935                 (void) untimeout(pcan_p->pcan_connect_timeout_id);
 936                 pcan_p->pcan_connect_timeout_id = 0;
 937         }
 938 
 939         if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
 940                 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
 941                 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
 942         }
 943         mutex_enter(&pcan_p->pcan_glock);
 944         if (pcan_p->pcan_flag & PCAN_CARD_INTREN) {
 945                 pcan_stop_locked(pcan_p);
 946                 pcan_p->pcan_flag |= PCAN_PLUMBED;
 947         }
 948         pcan_p->pcan_flag &= ~PCAN_CARD_READY;
 949         mutex_exit(&pcan_p->pcan_glock);
 950 
 951         if (ret = csx_ReleaseConfiguration(pcan_p->pcan_chdl, NULL))
 952                 cmn_err(CE_WARN, "pcan: ReleaseConfiguration failed %x\n", ret);
 953 
 954         bzero(&irq, sizeof (irq));
 955         if (ret = csx_ReleaseIRQ(pcan_p->pcan_chdl, &irq))
 956                 cmn_err(CE_WARN, "pcan: ReleaseIRQ failed %x\n", ret);
 957 
 958         ddi_remove_softintr(pcan_p->pcan_softint_id);
 959         pcan_p->pcan_softint_id  = 0;
 960 
 961         bzero(&io, sizeof (io));
 962         io.BasePort1.handle = pcan_p->pcan_port;
 963         io.NumPorts1 = 16;
 964         if (ret = csx_ReleaseIO(pcan_p->pcan_chdl, &io))
 965                 cmn_err(CE_WARN, "pcan: Release IO failed %x\n", ret);
 966 
 967         pcan_p->pcan_port = 0;
 968         PCANDBG((CE_NOTE, "pcan: removed\n"));
 969 }
 970 
 971 /*
 972  * gld operation interface routines
 973  */
 974 static int
 975 pcan_start(void *arg)
 976 {
 977         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
 978 
 979         mutex_enter(&pcan_p->pcan_glock);
 980         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
 981                 mutex_exit(&pcan_p->pcan_glock);
 982                 return (PCAN_FAIL);
 983         }
 984         (void) pcan_loaddef(pcan_p);
 985         pcan_start_locked(pcan_p);
 986         mutex_exit(&pcan_p->pcan_glock);
 987         return (PCAN_SUCCESS);
 988 }
 989 
 990 static void
 991 pcan_stop(void *arg)
 992 {
 993         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
 994 
 995         mutex_enter(&pcan_p->pcan_glock);
 996         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
 997                 mutex_exit(&pcan_p->pcan_glock);
 998                 return;
 999         }
1000         pcan_stop_locked(pcan_p);
1001         mutex_exit(&pcan_p->pcan_glock);
1002         if (pcan_p->pcan_connect_timeout_id != 0) {
1003                 (void) untimeout(pcan_p->pcan_connect_timeout_id);
1004                 pcan_p->pcan_connect_timeout_id = 0;
1005         }
1006 }
1007 
1008 /*
1009  * mac address can only be set in 'disable' state and
1010  * be effective after 'enable' state.
1011  */
1012 static int
1013 pcan_saddr(void *arg, const uint8_t *macaddr)
1014 {
1015         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1016         int ret = PCAN_SUCCESS;
1017         ether_copy(macaddr, pcan_p->pcan_mac_addr);
1018 
1019         mutex_enter(&pcan_p->pcan_glock);
1020         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1021                 ret = PCAN_FAIL;
1022                 goto done;
1023         }
1024         ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
1025         if (pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
1026                 cmn_err(CE_WARN, "pcan set mac addr: failed\n");
1027                 ret = PCAN_FAIL;
1028                 goto done;
1029         }
1030         if (pcan_config_mac(pcan_p)) {
1031                 cmn_err(CE_WARN, "pcan set mac addr: config_mac failed\n");
1032                 ret = PCAN_FAIL;
1033                 goto done;
1034         }
1035         if (pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
1036                 cmn_err(CE_WARN, "pcan set mac addr: failed\n");
1037                 ret = PCAN_FAIL;
1038         }
1039 done:
1040         mutex_exit(&pcan_p->pcan_glock);
1041         return (ret);
1042 }
1043 
1044 /*
1045  * send a packet out for pccard
1046  */
1047 static int
1048 pcan_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
1049 {
1050         char *buf, *buf_p;
1051         an_txfrm_t *frm_p;
1052 #ifdef PCAN_SEND_DEBUG
1053         struct an_ltv_status radio_status;
1054 #endif /* PCAN_SEND_DEBUG */
1055         uint16_t pkt_len, xmt_id, ring_idx, r = 0;
1056         struct ieee80211_frame *wh;
1057         int i = 0;
1058 
1059         mutex_enter(&pcan_p->pcan_glock);
1060         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1061                 mutex_exit(&pcan_p->pcan_glock);
1062                 freemsg(mblk_p);
1063                 return (PCAN_SUCCESS);          /* drop packet */
1064         }
1065         if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) {   /* link down */
1066                 PCANDBG((CE_NOTE, "pcan: link down, dropped\n"));
1067                 pcan_p->glds_nocarrier++;
1068                 mutex_exit(&pcan_p->pcan_glock);
1069                 freemsg(mblk_p);
1070                 return (PCAN_SUCCESS);          /* drop packet */
1071         }
1072         mutex_exit(&pcan_p->pcan_glock);
1073         if (pullupmsg(mblk_p, -1) == 0) {
1074                 cmn_err(CE_NOTE, "pcan send: pullupmsg failed\n");
1075                 freemsg(mblk_p);
1076                 return (PCAN_SUCCESS);          /* drop packet */
1077         }
1078         wh = (struct ieee80211_frame *)mblk_p->b_rptr;
1079 
1080         mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1081         ring_idx = pcan_p->pcan_txring.an_tx_prod;
1082         pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) & AN_TX_RING_MASK;
1083 
1084         /* check whether there is a xmt buffer available */
1085         while ((i < AN_TX_RING_CNT) &&
1086             (pcan_p->pcan_txring.an_tx_ring[ring_idx])) {
1087                 ring_idx = pcan_p->pcan_txring.an_tx_prod;
1088                 pcan_p->pcan_txring.an_tx_prod =
1089                     (ring_idx + 1) & AN_TX_RING_MASK;
1090                 i++;
1091         }
1092 
1093         if (i == AN_TX_RING_CNT) {
1094                 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1095                 PCANDBG((CE_NOTE, "pcan: ring full, retrying\n"));
1096                 mutex_enter(&pcan_p->pcan_glock);
1097                 pcan_p->pcan_reschedule_need = B_TRUE;
1098                 mutex_exit(&pcan_p->pcan_glock);
1099                 pcan_p->glds_noxmtbuf++;
1100                 return (PCAN_FAIL);
1101         }
1102         xmt_id = pcan_p->pcan_txring.an_tx_fids[ring_idx];
1103         pcan_p->pcan_txring.an_tx_ring[ring_idx] = xmt_id;
1104         mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1105 
1106         buf = kmem_zalloc(PCAN_NICMEM_SZ, KM_SLEEP); /* too big for stack */
1107         buf_p = (ulong_t)buf & 1 ? buf + 1 : buf;   /* 16-bit round up */
1108         frm_p = (an_txfrm_t *)buf_p;
1109 
1110 #ifdef DEBUG
1111         if (pcan_debug & PCAN_DBG_SEND) {
1112                 cmn_err(CE_NOTE, "pcan send: packet from plugin");
1113                 for (i = 0; i < MBLKL(mblk_p); i++)
1114                         cmn_err(CE_NOTE, "%x: %x\n", i,
1115                             *((unsigned char *)mblk_p->b_rptr + i));
1116         }
1117 #endif
1118         pkt_len = msgdsize(mblk_p);
1119         if (pkt_len > PCAN_NICMEM_SZ - sizeof (an_txfrm_t)) {
1120                 cmn_err(CE_WARN, "pcan send: mblk is too long");
1121                 kmem_free(buf, PCAN_NICMEM_SZ);
1122                 freemsg(mblk_p);
1123                 return (PCAN_SUCCESS);          /* drop packet */
1124         }
1125         if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
1126             IEEE80211_FC1_DIR_TODS) {
1127                 kmem_free(buf, PCAN_NICMEM_SZ);
1128                 freemsg(mblk_p);
1129                 return (PCAN_SUCCESS);          /* drop packet */
1130         }
1131 
1132         /* initialize xmt frame header, payload_len must be stored in LE */
1133         bzero(frm_p, sizeof (an_txfrm_t) + 2);
1134         frm_p->an_tx_ctl = AN_TXCTL_8023;
1135 
1136         /*
1137          * mblk sent down from plugin includes station mode 802.11 frame and
1138          * llc, so we here need to remove them and add an ethernet header.
1139          */
1140         pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
1141             + 2;
1142         bcopy(wh->i_addr3, buf_p + 0x38, ETHERADDRL); /* dst macaddr */
1143         bcopy(wh->i_addr2, buf_p + 0x3e, ETHERADDRL); /* src macaddr */
1144         *((uint16_t *)(buf_p + 0x36)) = pkt_len;
1145         bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
1146             - 2, buf_p + 0x44, pkt_len);
1147 
1148         if (pkt_len & 1) {  /* round up to 16-bit boundary and pad 0 */
1149                 buf_p[pkt_len + 0x44] = 0;
1150                 pkt_len++;
1151         }
1152         ASSERT(pkt_len <= PCAN_NICMEM_SZ);
1153 #ifdef DEBUG
1154         if (pcan_debug & PCAN_DBG_SEND) {
1155                 cmn_err(CE_NOTE, "pcan send: packet to hardware--pkt_len=%x",
1156                     pkt_len);
1157                 for (i = 0; i < pkt_len + 4; i++)
1158                         cmn_err(CE_NOTE, "%x: %x\n", i,
1159                             *((unsigned char *)buf_p + 0x36 + i));
1160         }
1161 #endif
1162         mutex_enter(&pcan_p->pcan_glock);
1163         (void) WRCH1(pcan_p, xmt_id, 0, (uint16_t *)buf_p, 0x38); /* frm */
1164         (void) WRPKT(pcan_p, xmt_id, 0x38, (uint16_t *)(buf_p + 0x38),
1165             pkt_len + 12);
1166         r = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id);
1167         mutex_exit(&pcan_p->pcan_glock);
1168 
1169         PCANDBG((CE_NOTE, "pcan: pkt_len=0x44+%x=%x xmt=%x ret=%x\n",
1170             pkt_len, 0x44 + pkt_len, xmt_id, ring_idx));
1171         kmem_free(buf, PCAN_NICMEM_SZ);
1172 #ifdef PCAN_SEND_DEBUG
1173         if (pkt_len = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &radio_status)) {
1174                 PCANDBG((CE_NOTE, "pcan: bad radio status %x\n", pkt_len));
1175         } else {
1176                 PCANDBG((CE_NOTE, "pcan: radio status:\n"));
1177         }
1178 #endif /* PCAN_SEND_DEBUG */
1179         if (r)
1180                 return (PCAN_FAIL);
1181         else {
1182                 freemsg(mblk_p);
1183                 return (PCAN_SUCCESS);
1184         }
1185 }
1186 
1187 /*
1188  * send a packet out for PCI/MiniPCI card
1189  */
1190 static int
1191 pcian_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
1192 {
1193         char *buf;
1194         uint16_t pkt_len = msgdsize(mblk_p), ring_idx;
1195         uint32_t i;
1196         struct ieee80211_frame *wh;
1197         struct an_card_tx_desc an_tx_desc;
1198 
1199         ring_idx = pcan_p->pcan_txring.an_tx_prod;
1200 
1201         mutex_enter(&pcan_p->pcan_glock);
1202         if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) {   /* link down */
1203                 mutex_exit(&pcan_p->pcan_glock);
1204                 pcan_p->glds_nocarrier++;
1205                 freemsg(mblk_p);
1206                 return (PCAN_SUCCESS);          /* drop packet */
1207         }
1208         mutex_exit(&pcan_p->pcan_glock);
1209         if (pullupmsg(mblk_p, -1) == 0) {
1210                 cmn_err(CE_NOTE, "pcan(pci) send: pullupmsg failed\n");
1211                 freemsg(mblk_p);
1212                 return (PCAN_SUCCESS);          /* drop packet */
1213         }
1214         wh = (struct ieee80211_frame *)mblk_p->b_rptr;
1215 
1216         mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1217         if ((pcan_p->pcan_flag & PCAN_CARD_SEND) &&
1218             (ring_idx == pcan_p->pcan_txring.an_tx_cons)) {
1219                 pcan_p->glds_noxmtbuf++;
1220                 pcan_p->pcan_reschedule_need = B_TRUE;
1221                 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1222                 return (PCAN_FAIL);
1223         }
1224         mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1225 
1226 #ifdef DEBUG
1227         if (pcan_debug & PCAN_DBG_SEND) {
1228                 cmn_err(CE_NOTE, "pcan(pci) send: packet from plugin");
1229                 for (i = 0; i < MBLKL(mblk_p); i++)
1230                         cmn_err(CE_NOTE, "%x: %x\n", i,
1231                             *((unsigned char *)mblk_p->b_rptr + i));
1232         }
1233 #endif
1234         mutex_enter(&pcan_p->pcan_glock);
1235 
1236         buf = pcan_p->pcan_tx[ring_idx].dma_virtaddr;
1237         bzero(buf, AN_TX_BUFFER_SIZE);
1238 
1239         /*
1240          * mblk sent down from plugin includes station mode 802.11 frame and
1241          * llc, so we here need to remove them and add an ethernet header.
1242          */
1243         *((uint16_t *)(buf + 8)) = htons(AN_TXCTL_8023);
1244         pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
1245             + 2;
1246         bcopy(wh->i_addr3, buf + 0x38, ETHERADDRL); /* dst macaddr */
1247         bcopy(wh->i_addr2, buf + 0x3e, ETHERADDRL); /* src macaddr */
1248         *((uint16_t *)(buf + 0x36)) = pkt_len;
1249         bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
1250             - 2, buf + 0x44, pkt_len);
1251 
1252 #ifdef DEBUG
1253         if (pcan_debug & PCAN_DBG_SEND) {
1254                 cmn_err(CE_NOTE, "pcan(pci) send: packet to hardware "
1255                     "pkt_len=%x", pkt_len);
1256                 for (i = 0; i < pkt_len + 14; i++)
1257                         cmn_err(CE_NOTE, "%x: %x\n", i,
1258                             *((unsigned char *)buf + 0x36 + i));
1259         }
1260 #endif
1261         bzero(&an_tx_desc, sizeof (an_tx_desc));
1262         an_tx_desc.an_offset = 0;
1263         an_tx_desc.an_eoc = (ring_idx == (AN_MAX_TX_DESC-1) ? 1 : 0);
1264         an_tx_desc.an_valid = 1;
1265         an_tx_desc.an_len =  0x44 + pkt_len;
1266         an_tx_desc.an_phys  = pcan_p->pcan_tx[ring_idx].dma_physaddr;
1267         for (i = 0; i < sizeof (an_tx_desc) / 4; i++) {
1268                 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET +
1269                     (ring_idx * sizeof (an_tx_desc)) + (i * 4),
1270                     ((uint32_t *)&an_tx_desc)[i]);
1271         }
1272 
1273         mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1274         pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) % AN_MAX_TX_DESC;
1275         pcan_p->pcan_flag |= PCAN_CARD_SEND;
1276         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
1277         mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1278 
1279         freemsg(mblk_p);
1280         mutex_exit(&pcan_p->pcan_glock);
1281         return (PCAN_SUCCESS);
1282 }
1283 
1284 static mblk_t *
1285 pcan_tx(void *arg, mblk_t *mp)
1286 {
1287         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1288         mblk_t *next;
1289         int ret = 0;
1290 
1291         ASSERT(mp != NULL);
1292         mutex_enter(&pcan_p->pcan_glock);
1293         if ((pcan_p->pcan_flag & (PCAN_CARD_LINKUP | PCAN_CARD_READY)) !=
1294             (PCAN_CARD_LINKUP | PCAN_CARD_READY)) {
1295                 mutex_exit(&pcan_p->pcan_glock);
1296                 freemsgchain(mp);
1297                 return (NULL);
1298         }
1299         mutex_exit(&pcan_p->pcan_glock);
1300         while (mp != NULL) {
1301                 next =  mp->b_next;
1302                 mp->b_next = NULL;
1303 
1304                 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1305                         ret = pcian_send(pcan_p, mp);
1306                 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1307                         ret = pcan_send(pcan_p, mp);
1308                 }
1309                 if (ret) {
1310                         mp->b_next = next;
1311                         break;
1312                 }
1313                 mp = next;
1314         }
1315         return (mp);
1316 }
1317 
1318 /*
1319  * this driver is porting from freebsd, the code in freebsd
1320  * doesn't show how to set promiscous mode.
1321  */
1322 /*ARGSUSED*/
1323 static int
1324 pcan_prom(void *arg, boolean_t on)
1325 {
1326         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1327         int ret = PCAN_SUCCESS;
1328 
1329         mutex_enter(&pcan_p->pcan_glock);
1330         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1331                 ret = PCAN_FAIL;
1332         }
1333         mutex_exit(&pcan_p->pcan_glock);
1334         return (ret);
1335 }
1336 
1337 /*ARGSUSED*/
1338 static int
1339 pcan_gstat(void *arg, uint_t statitem, uint64_t *val)
1340 {
1341         uint16_t i;
1342         int ret = PCAN_SUCCESS;
1343         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1344         uint64_t *cntr_p = pcan_p->pcan_cntrs_s;
1345 
1346         PCANDBG((CE_NOTE, "pcan: gstat called\n"));
1347 
1348         mutex_enter(&pcan_p->pcan_glock);
1349         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1350                 ret = PCAN_FAIL;
1351                 goto done;
1352         }
1353         if (pcan_get_ltv(pcan_p, sizeof (pcan_p->an_stats),
1354             AN_RID_16BITS_DELTACLR, (uint16_t *)&pcan_p->an_stats)) {
1355                 cmn_err(CE_WARN, "pcan kstat: get ltv(32 delta statistics)"
1356                     " failed \n");
1357                 ret = PCAN_FAIL;
1358                 goto done;
1359         }
1360         for (i = 0; i < ANC_STAT_CNT; i++) {
1361                 cntr_p[i] += *((uint16_t *)&pcan_p->an_stats + 1 + i);
1362         }
1363         if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
1364                 cmn_err(CE_WARN, "pcan kstat: read status failed \n");
1365                 ret = PCAN_FAIL;
1366                 goto done;
1367         }
1368 
1369         switch (statitem) {
1370         case MAC_STAT_IFSPEED:
1371                 *val = 500000 * pcan_p->an_status.an_cur_tx_rate;
1372                 break;
1373         case MAC_STAT_NOXMTBUF:
1374                 *val = pcan_p->glds_noxmtbuf;
1375                 break;
1376         case MAC_STAT_NORCVBUF:
1377                 *val = pcan_p->glds_norcvbuf;
1378                 break;
1379         case MAC_STAT_IERRORS:
1380                 *val = cntr_p[ANC_RX_OVERRUNS] +
1381                     cntr_p[ANC_RX_PLCP_CSUM_ERRS] +
1382                     cntr_p[ANC_RX_PLCP_FORMAT_ERRS] +
1383                     cntr_p[ANC_RX_PLCP_LEN_ERRS] +
1384                     cntr_p[ANC_RX_MAC_CRC_ERRS] +
1385                     cntr_p[ANC_RX_WEP_ERRS];
1386                 break;
1387         case MAC_STAT_OERRORS:
1388                 *val = cntr_p[ANC_TX_HOST_FAILED];
1389                 break;
1390         case MAC_STAT_RBYTES:
1391                 *val = cntr_p[ANC_HOST_RX_BYTES];
1392                 break;
1393         case MAC_STAT_IPACKETS:
1394                 *val = cntr_p[ANC_RX_HOST_UCASTS];
1395                 break;
1396         case MAC_STAT_OBYTES:
1397                 *val = cntr_p[ANC_HOST_TX_BYTES];
1398                 break;
1399         case MAC_STAT_OPACKETS:
1400                 *val = cntr_p[ANC_TX_HOST_UCASTS];
1401                 break;
1402         case WIFI_STAT_TX_FAILED:
1403                 *val = cntr_p[ANC_TX_HOST_FAILED];
1404                 break;
1405         case WIFI_STAT_TX_RETRANS:
1406                 *val = cntr_p[ANC_HOST_RETRIES];
1407                 break;
1408         case WIFI_STAT_FCS_ERRORS:
1409                 *val = cntr_p[ANC_RX_MAC_CRC_ERRS];
1410                 break;
1411         case WIFI_STAT_WEP_ERRORS:
1412                 *val = cntr_p[ANC_RX_WEP_ERRS];
1413                 break;
1414         case WIFI_STAT_MCAST_TX:
1415                 *val = cntr_p[ANC_TX_HOST_MCASTS];
1416                 break;
1417         case WIFI_STAT_MCAST_RX:
1418                 *val = cntr_p[ANC_RX_HOST_MCASTS];
1419                 break;
1420         case WIFI_STAT_TX_FRAGS:
1421         case WIFI_STAT_RX_FRAGS:
1422                 *val = 0;
1423                 break;
1424         case WIFI_STAT_RTS_SUCCESS:
1425                 *val = cntr_p[ANC_TX_RTS_OK];
1426                 break;
1427         case WIFI_STAT_RTS_FAILURE:
1428                 *val = cntr_p[ANC_NO_CTS];
1429                 break;
1430         case WIFI_STAT_ACK_FAILURE:
1431                 *val = cntr_p[ANC_NO_ACK];
1432                 break;
1433         case WIFI_STAT_RX_DUPS:
1434                 *val = cntr_p[ANC_RX_DUPS];
1435                 break;
1436         default:
1437                 ret = ENOTSUP;
1438         }
1439 
1440 
1441 done:
1442         mutex_exit(&pcan_p->pcan_glock);
1443         return (ret);
1444 }
1445 
1446 /*
1447  * this driver is porting from freebsd, the code in freebsd
1448  * doesn't show how to set multi address.
1449  */
1450 /*ARGSUSED*/
1451 static int
1452 pcan_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p)
1453 {
1454         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1455 
1456         mutex_enter(&pcan_p->pcan_glock);
1457         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1458                 mutex_exit(&pcan_p->pcan_glock);
1459                 return (PCAN_FAIL);
1460         }
1461         mutex_exit(&pcan_p->pcan_glock);
1462         return (PCAN_SUCCESS);
1463 }
1464 
1465 static uint_t
1466 pcan_info_softint(caddr_t arg)
1467 {
1468         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1469         wifi_data_t wd = { 0 };
1470         uint16_t link;
1471         uint32_t link_up;
1472 
1473         mutex_enter(&pcan_p->pcan_glock);
1474         if (pcan_p->pcan_info_softint_pending != 1) {
1475                 mutex_exit(&pcan_p->pcan_glock);
1476                 return (DDI_INTR_UNCLAIMED);
1477         }
1478 
1479         PCAN_READ(pcan_p, AN_LINKSTAT(pcan_p), link);
1480         link_up = pcan_p->pcan_flag & PCAN_CARD_LINKUP;
1481         if ((link == AN_LINKSTAT_ASSOCIATED) && !link_up) {
1482                 pcan_p->pcan_flag |= PCAN_CARD_LINKUP;
1483                 mutex_exit(&pcan_p->pcan_glock);
1484                 if (pcan_p->pcan_connect_timeout_id != 0) {
1485                         (void) untimeout(pcan_p->pcan_connect_timeout_id);
1486                         pcan_p->pcan_connect_timeout_id = 0;
1487                 }
1488                 mac_link_update(GLD3(pcan_p), LINK_STATE_UP);
1489                 mutex_enter(&pcan_p->pcan_glock);
1490                 (void) pcan_status_ltv(PCAN_READ_LTV, pcan_p,
1491                     &pcan_p->an_status);
1492                 bcopy(pcan_p->an_status.an_cur_bssid, wd.wd_bssid, 6);
1493                 wd.wd_secalloc = WIFI_SEC_NONE;
1494                 wd.wd_opmode = IEEE80211_M_STA;
1495                 (void) mac_pdata_update(pcan_p->pcan_mh, &wd,
1496                     sizeof (wd));
1497 #ifdef DEBUG
1498                 if (pcan_debug & PCAN_DBG_LINKINFO) {
1499                         cmn_err(CE_NOTE, "pcan: link Up, chan=%d, "
1500                             "ssid=\"%s\""
1501                             " (%02x:%02x:%02x:%02x:%02x:%02x)\n",
1502                             pcan_p->an_status.an_channel_set,
1503                             pcan_p->an_status.an_ssid,
1504                             pcan_p->an_status.an_cur_bssid[0],
1505                             pcan_p->an_status.an_cur_bssid[1],
1506                             pcan_p->an_status.an_cur_bssid[2],
1507                             pcan_p->an_status.an_cur_bssid[3],
1508                             pcan_p->an_status.an_cur_bssid[4],
1509                             pcan_p->an_status.an_cur_bssid[5]);
1510                 }
1511 #endif
1512         }
1513         if ((link != AN_LINKSTAT_ASSOCIATED) && link_up) {
1514                 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
1515 #ifdef DEBUG
1516                 if (pcan_debug & PCAN_DBG_LINKINFO) {
1517                         cmn_err(CE_NOTE, "pcan: link Down 0x%x\n", link);
1518                 }
1519 #endif
1520                 if (link != AN_LINKSTAT_SYNCLOST_HOSTREQ) {
1521                         pcan_p->pcan_connect_timeout_id =
1522                             timeout(pcan_connect_timeout,
1523                             pcan_p, drv_usectohz(1000));
1524                 }
1525                 mutex_exit(&pcan_p->pcan_glock);
1526                 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
1527                 mutex_enter(&pcan_p->pcan_glock);
1528         }
1529 
1530         pcan_p->pcan_info_softint_pending = 0;
1531         mutex_exit(&pcan_p->pcan_glock);
1532         return (DDI_INTR_CLAIMED);
1533 }
1534 
1535 static uint_t
1536 pcan_intr(caddr_t arg)
1537 {
1538         uint16_t stat;
1539         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1540 
1541         mutex_enter(&pcan_p->pcan_glock);
1542         if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
1543             (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
1544                 mutex_exit(&pcan_p->pcan_glock);
1545                 return (DDI_INTR_UNCLAIMED);
1546         }
1547         PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1548 
1549         if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
1550                 mutex_exit(&pcan_p->pcan_glock);
1551                 return (DDI_INTR_UNCLAIMED);
1552         }
1553 
1554         PCAN_DISABLE_INTR(pcan_p);
1555         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), ~AN_INTRS(pcan_p));
1556 
1557         PCANDBG((CE_NOTE, "pcan intr: stat=%x pcan_flags=%x\n", stat,
1558             pcan_p->pcan_flag));
1559 
1560         if (stat & AN_EV_AWAKE) {
1561                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
1562                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
1563         }
1564         if (stat & AN_EV_LINKSTAT) {
1565                 pcan_p->pcan_info_softint_pending = 1;
1566                 ddi_trigger_softintr(pcan_p->pcan_info_softint_id);
1567                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_LINKSTAT);
1568         }
1569         if (stat & AN_EV_RX) {
1570                 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1571                         pcian_rcv(pcan_p);
1572                 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1573                         pcan_rcv(pcan_p);
1574                 }
1575                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_RX);
1576         }
1577         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1578                 if (stat & AN_EV_TX_CPY) {
1579                         (void) pcan_txdone(pcan_p, stat & AN_EV_TX_CPY);
1580                         if (pcan_p->pcan_reschedule_need == B_TRUE) {
1581                                 mac_tx_update(GLD3(pcan_p));
1582                                 pcan_p->pcan_reschedule_need = B_FALSE;
1583                         }
1584                         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_CPY);
1585         }
1586         }
1587         if (stat & AN_EV_TX) {
1588                 if (pcan_txdone(pcan_p, stat & AN_EV_TX) == 0) {
1589                         if (pcan_p->pcan_reschedule_need == B_TRUE) {
1590                                 mac_tx_update(GLD3(pcan_p));
1591                                 pcan_p->pcan_reschedule_need = B_FALSE;
1592                         }
1593                 }
1594                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX);
1595         }
1596         if (stat & AN_EV_TX_EXC) {
1597                 if (pcan_txdone(pcan_p, stat & AN_EV_TX_EXC) == 0) {
1598                         if (pcan_p->pcan_reschedule_need == B_TRUE) {
1599                                 mutex_exit(&pcan_p->pcan_glock);
1600                                 mac_tx_update(GLD3(pcan_p));
1601                                 mutex_enter(&pcan_p->pcan_glock);
1602                                 pcan_p->pcan_reschedule_need = B_FALSE;
1603                         }
1604                 }
1605                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_EXC);
1606         }
1607         if (stat & AN_EV_ALLOC) {
1608                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
1609                 PCANDBG((CE_NOTE, "pcan intr: nicmem alloc done\n"));
1610         }
1611         if (stat & AN_EV_MIC) {
1612                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_MIC);
1613         }
1614         PCAN_ENABLE_INTR(pcan_p);
1615         mutex_exit(&pcan_p->pcan_glock);
1616         return (DDI_INTR_CLAIMED);
1617 }
1618 
1619 static uint_t
1620 pcan_intr_hi(caddr_t arg)
1621 {
1622         uint16_t stat;
1623         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1624 
1625         mutex_enter(&pcan_p->pcan_glock);
1626         if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
1627             (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
1628                 mutex_exit(&pcan_p->pcan_glock);
1629                 return (DDI_INTR_UNCLAIMED);
1630         }
1631         PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1632         PCANDBG((CE_NOTE, "pcan intr(hi): stat=%x pcan_flags=%x\n", stat,
1633             pcan_p->pcan_flag));
1634 
1635         if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
1636                 mutex_exit(&pcan_p->pcan_glock);
1637                 return (DDI_INTR_UNCLAIMED);
1638         }
1639         /* disable interrupt without ack */
1640         PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0);
1641         mutex_exit(&pcan_p->pcan_glock);
1642         ddi_trigger_softintr(pcan_p->pcan_softint_id);
1643         return (DDI_INTR_CLAIMED);
1644 }
1645 
1646 /*
1647  * retrieve data from pccard
1648  */
1649 static void
1650 pcan_rcv(pcan_maci_t *pcan_p)
1651 {
1652         uint16_t id, off, ret, data_len, pkt_stat, frm_ctl;
1653         an_rxfrm_t frm;
1654         struct ieee80211_llc *llc;
1655 
1656         mblk_t *mp = allocb(PCAN_NICMEM_SZ, BPRI_MED);
1657         if (!mp) {
1658                 cmn_err(CE_WARN, "pcan: failed to alloc rcv buf");
1659                 pcan_p->glds_norcvbuf++;
1660                 return;
1661         }
1662         ASSERT(mp->b_rptr == mp->b_wptr);
1663 
1664         PCAN_READ(pcan_p, AN_RX_FID, id);
1665         if (id == AN_INVALID_FID) {
1666                 PCANDBG((CE_NOTE, "pcan rcv: can't get rx_fid\n"));
1667                 pcan_p->glds_norcvbuf++;
1668                 ret = PCAN_FAIL;
1669                 goto done;
1670         }
1671         if (ret = RDCH0(pcan_p, id, 0, (uint16_t *)&frm, sizeof (frm))) {
1672                 PCANDBG((CE_NOTE, "pcan rcv: read frm err %x\n", ret));
1673                 goto done;
1674         }
1675         off = sizeof (frm);
1676         if (frm.an_rx_status) {
1677                 PCANDBG((CE_NOTE, "pcan rcv: err stat %x\n", frm.an_rx_status));
1678                 ret = frm.an_rx_status;
1679                 goto done;
1680         }
1681         PCANDBG((CE_NOTE, "pcan rcv: payload_len=%x gap_len=%x\n",
1682             frm.an_rx_payload_len, frm.an_gaplen));
1683         if (frm.an_rx_payload_len > PCAN_NICMEM_SZ ||
1684             frm.an_gaplen > AN_RXGAP_MAX) {
1685                 PCANDBG((CE_NOTE, "pcan rcv: bad len\n"));
1686                 ret = PCAN_FAIL;
1687                 goto done;
1688         }
1689         if (ret = RDCH0(pcan_p, id, off, &pkt_stat, sizeof (pkt_stat))) {
1690                 PCANDBG((CE_NOTE, "pcan rcv: pkt status err %x\n", ret));
1691                 ret = PCAN_FAIL;
1692                 goto done;
1693         }
1694         off += sizeof (pkt_stat);
1695         if (ret = RDCH0(pcan_p, id, off, &data_len, sizeof (data_len))) {
1696                 PCANDBG((CE_NOTE, "pcan rcv: payload len err %x\n", ret));
1697                 ret = PCAN_FAIL;
1698                 goto done;
1699         }
1700         off += sizeof (data_len);
1701         off += ETHERADDRL << 1;
1702         PCANDBG((CE_NOTE, "pcan rcv: pkt_stat=%x payload_len=%x+c off=%x\n",
1703             pkt_stat, data_len, off));
1704 
1705 #ifdef DEBUG
1706         if (pcan_debug & PCAN_DBG_RCV) {
1707                 int i;
1708                 cmn_err(CE_NOTE, "pcan rcv: frm header\n");
1709                 for (i = 0; i < sizeof (frm); i++)
1710                         cmn_err(CE_NOTE, "%x: %x\n", i,
1711                             *((uint8_t *)&frm + i));
1712         }
1713 #endif
1714         /*
1715          * this driver deal with WEP by itself. so plugin always thinks no wep.
1716          */
1717         frm.an_frame_ctl &= ~(IEEE80211_FC1_WEP << 8);
1718         frm_ctl = frm.an_frame_ctl;
1719         PCAN_SWAP16((uint16_t *)&frm.an_frame_ctl,
1720             sizeof (struct ieee80211_frame));
1721         /*
1722          * discard those frames which are not from the AP we connect or
1723          * without 'ap->sta' direction
1724          */
1725         if (((pcan_p->an_config.an_opmode == AN_OPMODE_INFR_STATION)) &&
1726             ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) !=
1727             IEEE80211_FC1_DIR_FROMDS) ||
1728             bcmp(pcan_p->an_status.an_cur_bssid, frm.an_addr2, 6) != 0)) {
1729                 ret = PCAN_FAIL;
1730                 goto done;
1731         }
1732         bcopy(&frm.an_frame_ctl, mp->b_wptr,
1733             sizeof (struct ieee80211_frame));
1734         mp->b_wptr += sizeof (struct ieee80211_frame);
1735 
1736         /* the plugin need a llc here */
1737         llc = (struct ieee80211_llc *)mp->b_wptr;
1738         llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
1739         llc->illc_control = AN_SNAP_CONTROL;
1740         bzero(llc->illc_oc, sizeof (llc->illc_oc));
1741         mp->b_wptr += AN_SNAPHDR_LEN;
1742 
1743         /* read in the rest of data */
1744         data_len += data_len & 1;   /* adjust to word boundary */
1745         if (data_len > MBLKSIZE(mp)) {
1746                 cmn_err(CE_NOTE, "pcan rcv: data over length%x\n", data_len);
1747                 ret = PCAN_FAIL;
1748                 goto done;
1749         }
1750 
1751         if (ret = RDPKT(pcan_p, id, off, (uint16_t *)mp->b_wptr, data_len)) {
1752                 PCANDBG((CE_NOTE, "pcan rcv: err read data %x\n", ret));
1753         }
1754 done:
1755         if (ret) {
1756                 PCANDBG((CE_NOTE, "pcan rcv: rd data %x\n", ret));
1757                 freemsg(mp);
1758                 return;
1759         }
1760         mp->b_wptr += data_len;
1761 #ifdef DEBUG
1762         if (pcan_debug & PCAN_DBG_RCV) {
1763                 int i;
1764                 cmn_err(CE_NOTE, "pcan rcv: len=0x%x\n", data_len);
1765                 for (i = 0; i < data_len + sizeof (frm); i++)
1766                         cmn_err(CE_NOTE, "%x: %x\n", i,
1767                             *((uint8_t *)mp->b_rptr + i));
1768         }
1769 #endif
1770         mutex_exit(&pcan_p->pcan_glock);
1771         mac_rx(GLD3(pcan_p), NULL, mp);
1772         mutex_enter(&pcan_p->pcan_glock);
1773 }
1774 
1775 /*
1776  * retrieve data from mini-pci card
1777  */
1778 static void
1779 pcian_rcv(pcan_maci_t *pcan_p)
1780 {
1781         struct an_card_rx_desc an_rx_desc;
1782         char *buf;
1783         uint16_t ret = 0, data_len;
1784         int i, j;
1785         struct ieee80211_frame *frm;
1786         struct ieee80211_llc *llc;
1787 
1788         mblk_t *mp = allocb(AN_RX_BUFFER_SIZE, BPRI_MED);
1789         if (!mp) {
1790                 cmn_err(CE_WARN, "pcan(pci): failed to alloc rcv buf");
1791                 pcan_p->glds_norcvbuf++;
1792                 return;
1793         }
1794         ASSERT(mp->b_rptr == mp->b_wptr);
1795 
1796         for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
1797                 PCAN_AUX_GET32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
1798                     ((uint32_t *)&an_rx_desc)[i]);
1799         if (an_rx_desc.an_done && !an_rx_desc.an_valid) {
1800                 buf = pcan_p->pcan_rx[0].dma_virtaddr;
1801                 data_len = an_rx_desc.an_len;
1802 #ifdef DEBUG
1803                 if (pcan_debug & PCAN_DBG_RCV) {
1804                         cmn_err(CE_NOTE, "pcan(pci) rcv: data_len=%x",
1805                             data_len);
1806                         for (j = 0; j < data_len + 14; j++)
1807                                 cmn_err(CE_NOTE, "pcan_rcv %d: %x", j,
1808                                     *((uint8_t *)buf + j));
1809                 }
1810 #endif
1811                 if (data_len > MBLKSIZE(mp)) {
1812                         cmn_err(CE_NOTE, "pcan(pci) rcv: data over length%x\n",
1813                             data_len);
1814                         ret = PCAN_FAIL;
1815                         goto done;
1816                 }
1817                 /*
1818                  * minipci card receive an ethernet frame, so assembly a 802.11
1819                  * frame here manually.
1820                  */
1821                 frm = (struct ieee80211_frame *)mp->b_wptr;
1822                 bzero(frm, sizeof (*frm));
1823                 frm->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
1824                 frm->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
1825                 bcopy(pcan_p->an_status.an_cur_bssid, frm->i_addr2, 6);
1826                 bcopy(buf, frm->i_addr1, 6);
1827                 bcopy(buf + 6, frm->i_addr3, 6);
1828                 mp->b_wptr += sizeof (struct ieee80211_frame);
1829 
1830                 llc = (struct ieee80211_llc *)mp->b_wptr;
1831                 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
1832                 llc->illc_control = AN_SNAP_CONTROL;
1833                 bzero(llc->illc_oc, sizeof (llc->illc_oc));
1834                 mp->b_wptr += AN_SNAPHDR_LEN;
1835 
1836                 bcopy(buf + 12, mp->b_wptr, data_len);
1837                 mp->b_wptr += data_len;
1838 #ifdef DEBUG
1839                 if (pcan_debug & PCAN_DBG_RCV) {
1840                         int i;
1841                         cmn_err(CE_NOTE, "pcan(pci) rcv: len=0x%x\n", data_len);
1842                         for (i = 0; i < data_len + sizeof (*frm)
1843                             + sizeof (*llc); i++)
1844                                 cmn_err(CE_NOTE, "%x: %x\n", i,
1845                                     *((uint8_t *)mp->b_rptr + i));
1846                 }
1847 #endif
1848                 mutex_exit(&pcan_p->pcan_glock);
1849                 mac_rx(GLD3(pcan_p), NULL, mp);
1850                 mutex_enter(&pcan_p->pcan_glock);
1851         }
1852 done:
1853         bzero(&an_rx_desc, sizeof (an_rx_desc));
1854         an_rx_desc.an_valid = 1;
1855         an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
1856         an_rx_desc.an_done = 0;
1857         an_rx_desc.an_phys = pcan_p->pcan_rx[0].dma_physaddr;
1858 
1859         for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
1860                 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
1861                     ((uint32_t *)&an_rx_desc)[i]);
1862         if (ret) {
1863                 freemsg(mp);
1864         }
1865 }
1866 
1867 /*ARGSUSED*/
1868 static uint32_t
1869 pcan_txdone(pcan_maci_t *pcan_p, uint16_t err)
1870 {
1871         uint16_t fid, i, ring_idx;
1872         uint32_t ret = 0;
1873 
1874         PCAN_READ(pcan_p, AN_TX_CMP_FID(pcan_p), fid);
1875         mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1876         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1877                 if (pcan_p->pcan_flag & PCAN_CARD_SEND) {
1878                         ring_idx = pcan_p->pcan_txring.an_tx_cons;
1879                         pcan_p->pcan_txring.an_tx_cons =
1880                             (ring_idx + 1) % AN_MAX_TX_DESC;
1881                         if (pcan_p->pcan_txring.an_tx_prod ==
1882                             pcan_p->pcan_txring.an_tx_cons) {
1883                                 pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
1884                         }
1885                 }
1886                 ret = 0;
1887         } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1888                 for (i = 0; i < AN_TX_RING_CNT; i++) {
1889                         if (fid == pcan_p->pcan_txring.an_tx_ring[i]) {
1890                                 pcan_p->pcan_txring.an_tx_ring[i] = 0;
1891                                 break;
1892                         }
1893                 }
1894                 pcan_p->pcan_txring.an_tx_cons =
1895                     (pcan_p->pcan_txring.an_tx_cons + 1) & AN_TX_RING_MASK;
1896                 ret = (i == AN_TX_RING_CNT ? 1 : 0);
1897         }
1898         mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1899         return (ret);
1900 }
1901 
1902 /*
1903  * delay in which the mutex is not hold.
1904  * assuming the mutex has already been hold.
1905  */
1906 static void
1907 pcan_delay(pcan_maci_t *pcan_p, clock_t microsecs)
1908 {
1909         ASSERT(mutex_owned(&pcan_p->pcan_glock));
1910 
1911         mutex_exit(&pcan_p->pcan_glock);
1912         delay(drv_usectohz(microsecs));
1913         mutex_enter(&pcan_p->pcan_glock);
1914 }
1915 
1916 static void
1917 pcan_reset_backend(pcan_maci_t *pcan_p, int timeout)
1918 {
1919         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1920                 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
1921                 PCAN_DISABLE_INTR_CLEAR(pcan_p);
1922                 (void) pcan_set_cmd(pcan_p, AN_CMD_FW_RESTART, 0);
1923                 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP2, 0);
1924                 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
1925         } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1926                 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
1927                 (void) pcan_set_cmd0(pcan_p, AN_CMD_NOOP2, 0, 0, 0);
1928                 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), AN_CMD_FW_RESTART);
1929                 pcan_delay(pcan_p, timeout); /* wait for firmware restart */
1930 
1931                 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP, 0);
1932                 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
1933 
1934                 PCAN_DISABLE_INTR_CLEAR(pcan_p);
1935         }
1936 }
1937 
1938 /*
1939  * set command without the need of ACK.
1940  */
1941 static uint16_t
1942 pcan_set_cmd0(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t p0,
1943     uint16_t p1, uint16_t p2)
1944 {
1945         int i;
1946         uint16_t stat, r0, r1, r2;
1947 
1948         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1949                 for (i = 0; i < AN_TIMEOUT; i++) {
1950                         PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
1951                         if (!(stat & AN_CMD_BUSY))
1952                                 break;
1953                 }
1954                 if (i == AN_TIMEOUT) {
1955                         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
1956                             AN_EV_CLR_STUCK_BUSY);
1957                         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1958                         drv_usecwait(10);
1959                 }
1960                 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), p0);
1961                 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), p1);
1962                 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), p2);
1963         }
1964         PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
1965         for (i = 0; i < AN_TIMEOUT; i++) {
1966                 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1967                 if (stat & AN_EV_CMD)
1968                         break;
1969         }
1970         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1971                 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
1972                 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
1973                 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
1974                 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
1975                 if (stat & AN_CMD_BUSY)
1976                         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
1977                             AN_EV_CLR_STUCK_BUSY);
1978                 PCANDBG((CE_NOTE, "pcan set_cmd0: "
1979                     "stat=%x, r0=%x, r1=%x, r2=%x\n",
1980                     stat, r0, r1, r2));
1981         }
1982         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1983         return (i == AN_TIMEOUT ? PCAN_TIMEDOUT_ACCESS : PCAN_SUCCESS);
1984 }
1985 
1986 static uint16_t
1987 pcan_set_cmd(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t param)
1988 {
1989         int i;
1990         uint16_t stat, r0, r1, r2;
1991         uint16_t ret;
1992 
1993         if (((cmd == AN_CMD_ENABLE) &&
1994             ((pcan_p->pcan_flag & PCAN_ENABLED) != 0)) ||
1995             ((cmd == AN_CMD_DISABLE) &&
1996             ((pcan_p->pcan_flag & PCAN_ENABLED) == 0)))
1997                 return (PCAN_SUCCESS);
1998         for (i = 0; i < AN_TIMEOUT; i++) {
1999                 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
2000                 if (!(stat & AN_CMD_BUSY)) {
2001                         break;
2002                 }
2003         }
2004         if (i == AN_TIMEOUT) {
2005                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
2006                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2007                 drv_usecwait(10);
2008         }
2009 
2010         PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), param);
2011         PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), 0);
2012         PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), 0);
2013         PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
2014 
2015         for (i = 0; i < AN_TIMEOUT; i++) {
2016                 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
2017                 if (stat & AN_EV_CMD) {
2018                         break;
2019                 }
2020                 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
2021                 if (stat == cmd)
2022                         PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
2023         }
2024         if (i == AN_TIMEOUT) {
2025                 if (cmd == AN_CMD_FW_RESTART) {
2026                         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2027                         return (PCAN_SUCCESS);
2028                 }
2029 #ifdef DEBUG
2030                 if (pcan_debug & PCAN_DBG_CMD) {
2031                         cmn_err(CE_WARN, "pcan set_cmd: %x timeout stat=%x\n",
2032                             cmd, stat);
2033                 }
2034 #endif
2035                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2036                 return (PCAN_TIMEDOUT_CMD);
2037         }
2038 
2039         for (i = 0; i < AN_TIMEOUT; i++) {
2040                 PCAN_READ(pcan_p, AN_STATUS(pcan_p), stat);
2041                 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
2042                 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
2043                 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
2044                 if ((stat & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
2045                         break;
2046         }
2047         if (cmd == AN_CMD_FW_RESTART) {
2048                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2049                 return (PCAN_SUCCESS);
2050         }
2051         if (i == AN_TIMEOUT) {
2052 #ifdef DEBUG
2053                 if (pcan_debug & PCAN_DBG_CMD) {
2054                         cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: timeout "
2055                             "%x,%x,%x,%x\n", cmd, param, stat, r0, r1, r2);
2056                 }
2057 #endif
2058                 ret = PCAN_TIMEDOUT_ACCESS;
2059         } else {
2060                 if (stat & AN_STAT_CMD_RESULT) {
2061 #ifdef DEBUG
2062                         if (pcan_debug & PCAN_DBG_CMD) {
2063                                 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: failed "
2064                                     "%x,%x,%x,%x\n",
2065                                     cmd, param, stat, r0, r1, r2);
2066                         }
2067 #endif
2068                         ret = PCAN_TIMEDOUT_ACCESS;
2069                 } else {
2070                         ret = PCAN_SUCCESS;
2071                 }
2072         }
2073         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2074         PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
2075         if (stat & AN_CMD_BUSY)
2076                 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
2077         if (ret == PCAN_SUCCESS) {
2078                 if (cmd == AN_CMD_ENABLE)
2079                         pcan_p->pcan_flag |= PCAN_ENABLED;
2080                 if (cmd == AN_CMD_DISABLE)
2081                         pcan_p->pcan_flag &= (~PCAN_ENABLED);
2082         }
2083         return (ret);
2084 }
2085 
2086 static uint16_t
2087 pcan_set_ch(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t channel)
2088 {
2089         int i;
2090         uint16_t stat, select, offset;
2091 
2092         if (channel) {
2093                 select = AN_SEL1;
2094                 offset = AN_OFF1;
2095         } else {
2096                 select = AN_SEL0;
2097                 offset = AN_OFF0;
2098         }
2099         PCAN_WRITE(pcan_p, select, type);
2100         PCAN_WRITE(pcan_p, offset, off);
2101         for (i = 0; i < AN_TIMEOUT; i++) {
2102                 PCAN_READ(pcan_p, offset, stat);
2103                 if (!(stat & (AN_OFF_BUSY|AN_OFF_ERR)))
2104                         break;
2105         }
2106         if (stat & (AN_OFF_BUSY|AN_OFF_ERR)) { /* time out */
2107                 PCANDBG((CE_WARN, "pcan: set_ch%d %x %x TO %x\n",
2108                     channel, type, off, stat));
2109                 return (PCAN_TIMEDOUT_TARGET);
2110         }
2111         return (PCAN_SUCCESS);
2112 }
2113 
2114 static uint16_t
2115 pcan_get_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
2116 {
2117         uint16_t stat;
2118 
2119         PCANDBG((CE_NOTE, "pcan: get_ltv(%p,%x,%x,%p)\n",
2120             (void *)pcan_p, len, type, (void *)val_p));
2121         ASSERT(!(len & 1));
2122 
2123         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
2124                 uint32_t i;
2125                 struct an_card_rid_desc an_rid_desc;
2126                 struct an_ltv_gen *an_ltv;
2127                 if (!pcan_p->pcan_cmd.dma_virtaddr)
2128                         return (EIO);
2129                 an_rid_desc.an_valid = 1;
2130                 an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
2131                 an_rid_desc.an_rid = 0;
2132                 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
2133                 bzero(pcan_p->pcan_cmd.dma_virtaddr, AN_RID_BUFFER_SIZE);
2134 
2135                 for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
2136                         PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
2137                             ((uint32_t *)&an_rid_desc)[i]);
2138 
2139                 if (pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
2140                     AN_ACCESS_READ, type, 0, 0)) {
2141                         cmn_err(CE_WARN, "pcan get_ltv: set cmd error");
2142                         return (EIO);
2143                 }
2144 
2145                 an_ltv = (struct an_ltv_gen *)pcan_p->pcan_cmd.dma_virtaddr;
2146 #ifdef DEBUG
2147                 if (pcan_debug & PCAN_DBG_INFO) {
2148                         cmn_err(CE_NOTE, "pcan get_ltv: type=%x,"
2149                             "expected len=%d," "actual len=%d",
2150                             type, len, an_ltv->an_len);
2151                         for (i = 0; i < an_ltv->an_len; i++)
2152                                 cmn_err(CE_NOTE, "%d: %x", i,
2153                                     *(((uint8_t *)an_ltv) + i));
2154                 }
2155 #endif
2156                 if (an_ltv->an_len != len) {
2157                         PCANDBG((CE_WARN, "pcan get_ltv: rid=%x expected len=%d"
2158                             "actual: len=%d", type,
2159                             len, an_ltv->an_len));
2160                         /* return (EIO); */
2161                 }
2162                 bcopy(an_ltv, val_p, len);
2163         } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
2164                 len >>= 1;        /* convert bytes to 16-bit words */
2165 
2166                 /* 1. select read mode */
2167                 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
2168                     AN_ACCESS_READ, type))
2169                         return (stat);
2170 
2171                 /* 2. select Buffer Access Path (channel) 1 for PIO */
2172                 if (stat = pcan_set_ch(pcan_p, type, 0, 1))
2173                         return (stat);
2174 
2175                 /* 3. read length */
2176                 PCAN_READ(pcan_p, AN_DATA1, stat);
2177                 *val_p++ = stat;
2178                 if (stat != (len << 1)) {
2179                         PCANDBG((CE_NOTE, "pcan get_ltv[%x]:expect %x,"
2180                             "got %x\n", type, (len + 1) << 1, stat));
2181                         stat = (stat >> 1) - 1;
2182                         len = MIN(stat, len);
2183                 }
2184                 /* 4. read value */
2185                 for (stat = 0; stat < len - 1; stat++, val_p++) {
2186                         PCAN_READ_P(pcan_p, AN_DATA1, val_p, 1);
2187                 }
2188         }
2189         return (PCAN_SUCCESS);
2190 }
2191 
2192 static uint16_t
2193 pcan_put_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
2194 {
2195         uint16_t stat;
2196         int i;
2197 
2198         ASSERT(!(len & 1));
2199 
2200         if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
2201                 struct an_card_rid_desc an_rid_desc;
2202 
2203                 for (i = 0; i < AN_TIMEOUT; i++) {
2204                         PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
2205                         if (!(stat & AN_CMD_BUSY)) {
2206                                 break;
2207                         }
2208                 }
2209                 if (i == AN_TIMEOUT) {
2210                         cmn_err(CE_WARN, "pcan put_ltv: busy");
2211                 }
2212 
2213                 an_rid_desc.an_valid = 1;
2214                 an_rid_desc.an_len = len;
2215                 an_rid_desc.an_rid = type;
2216                 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
2217 
2218                 bcopy(val_p, pcan_p->pcan_cmd.dma_virtaddr,
2219                     an_rid_desc.an_len);
2220 
2221                 for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
2222                         PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
2223                             ((uint32_t *)&an_rid_desc)[i]);
2224                 pcan_delay(pcan_p, 100000);
2225                 stat = pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
2226                     AN_ACCESS_WRITE, type, 0, 0);
2227                 pcan_delay(pcan_p, 100000);
2228                 return (stat);
2229         } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
2230                 /* 0. select read mode first */
2231                 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
2232                     AN_ACCESS_READ, type))
2233                         return (stat);
2234 
2235                 /* 1. select Buffer Access Path (channel) 1 for PIO */
2236                 if (stat = pcan_set_ch(pcan_p, type, 0, 1))
2237                         return (stat);
2238 
2239                 /* 2. write length */
2240                 len >>= 1;                /* convert bytes to 16-bit words */
2241                 stat = len;
2242                 PCAN_WRITE(pcan_p, AN_DATA1, stat);
2243 
2244                 /* 3. write value */
2245                 val_p++;
2246                 for (stat = 0; stat < len-1; stat++, val_p++) {
2247                         PCAN_WRITE_P(pcan_p, AN_DATA1, val_p, 1);
2248                 }
2249 
2250                 /* 4. select write mode */
2251                 return (pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
2252                     AN_ACCESS_WRITE, type));
2253         }
2254         return (PCAN_FAIL);
2255 }
2256 
2257 /*ARGSUSED*/
2258 static uint16_t
2259 pcan_rdch0(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
2260         int len, int order)
2261 {
2262         ASSERT(!(len & 1));
2263 
2264         if (pcan_set_ch(pcan_p, type, off, 0) != PCAN_SUCCESS)
2265                 return (PCAN_FAIL);
2266         len >>= 1;
2267         for (off = 0; off < len; off++, buf_p++) {
2268                 PCAN_READ_P(pcan_p, AN_DATA0, buf_p, order);
2269         }
2270         return (PCAN_SUCCESS);
2271 }
2272 
2273 /*ARGSUSED*/
2274 static uint16_t
2275 pcan_wrch1(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
2276         int len, int order)
2277 {
2278         ASSERT(!(len & 1));
2279 
2280         if (pcan_set_ch(pcan_p, type, off, 1) != PCAN_SUCCESS)
2281                 return (PCAN_FAIL);
2282         len >>= 1;
2283         for (off = 0; off < len; off++, buf_p++) {
2284                 PCAN_WRITE_P(pcan_p, AN_DATA1, buf_p, order);
2285         }
2286         return (PCAN_SUCCESS);
2287 }
2288 
2289 static uint16_t
2290 pcan_status_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_status *status_p)
2291 {
2292         uint16_t ret, len;
2293 
2294         if (rw != PCAN_READ_LTV) {
2295                 cmn_err(CE_WARN, "pcan status_ltv: unsupported op %x", rw);
2296                 return (PCAN_FAIL);
2297         }
2298         if (ret = pcan_get_ltv(pcan_p, sizeof (*status_p), AN_RID_STATUS,
2299             (uint16_t *)status_p))
2300                 return (ret);
2301 
2302         PCAN_SWAP16_BUF(status_p->an_macaddr);
2303         PCAN_SWAP16_BUF(status_p->an_ssid);
2304         len = min(status_p->an_ssidlen, 31);
2305         status_p->an_ssid[len] = '\0';
2306         PCAN_SWAP16_BUF(status_p->an_ap_name);
2307         PCAN_SWAP16_BUF(status_p->an_cur_bssid);
2308         PCAN_SWAP16_BUF(status_p->an_prev_bssid1);
2309         PCAN_SWAP16_BUF(status_p->an_prev_bssid2);
2310         PCAN_SWAP16_BUF(status_p->an_prev_bssid3);
2311         PCAN_SWAP16_BUF(status_p->an_ap_ip_address);
2312         PCAN_SWAP16_BUF(status_p->an_carrier);
2313         return (PCAN_SUCCESS);
2314 }
2315 
2316 static uint16_t
2317 pcan_cfg_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_genconfig *cfg_p)
2318 {
2319         uint16_t ret;
2320         uint16_t rid = cfg_p == &pcan_p->an_config ?
2321             AN_RID_GENCONFIG : AN_RID_ACTUALCFG;
2322 
2323         if (rw == PCAN_READ_LTV) {
2324                 if (ret = pcan_get_ltv(pcan_p, sizeof (*cfg_p), rid,
2325                     (uint16_t *)cfg_p))
2326                         return (ret);
2327                 goto done;
2328         }
2329         PCAN_SWAP16_BUF(cfg_p->an_macaddr);
2330         PCAN_SWAP16_BUF(cfg_p->an_rates);
2331         if (ret = pcan_put_ltv(pcan_p, sizeof (*cfg_p),
2332             rid, (uint16_t *)cfg_p))
2333                 return (ret);
2334 done:
2335         PCAN_SWAP16_BUF(cfg_p->an_macaddr);
2336         PCAN_SWAP16_BUF(cfg_p->an_rates);
2337         return (ret);
2338 }
2339 
2340 static uint16_t
2341 pcan_cap_ltv(int rw, pcan_maci_t *pcan_p)
2342 {
2343         uint16_t ret;
2344 
2345         if (rw != PCAN_READ_LTV) {
2346                 cmn_err(CE_WARN, "pcan cap_ltv: unsupported op %x", rw);
2347                 return (PCAN_FAIL);
2348         }
2349         if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_caps),
2350             AN_RID_CAPABILITIES, (uint16_t *)&pcan_p->an_caps))
2351                 return (ret);
2352 
2353         PCAN_SWAP16_BUF(pcan_p->an_caps.an_oui);
2354         PCAN_SWAP16_BUF(pcan_p->an_caps.an_manufname);
2355         PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodname);
2356         PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodvers);
2357         PCAN_SWAP16_BUF(pcan_p->an_caps.an_oemaddr);
2358         PCAN_SWAP16_BUF(pcan_p->an_caps.an_aironetaddr);
2359         PCAN_SWAP16_BUF(pcan_p->an_caps.an_callid);
2360         PCAN_SWAP16_BUF(pcan_p->an_caps.an_supported_rates);
2361         return (PCAN_SUCCESS);
2362 }
2363 
2364 static uint16_t
2365 pcan_ssid_ltv(int rw, pcan_maci_t *pcan_p)
2366 {
2367         uint16_t ret;
2368 
2369         if (rw == PCAN_READ_LTV) {
2370                 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
2371                     AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
2372                         return (ret);
2373                 goto done;
2374         }
2375         PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
2376         PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
2377         PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
2378         if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
2379             AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
2380                 return (ret);
2381 done:
2382         PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
2383         PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
2384         PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
2385         return (ret);
2386 }
2387 
2388 static uint16_t
2389 pcan_aplist_ltv(int rw, pcan_maci_t *pcan_p)
2390 {
2391         uint16_t ret;
2392 
2393         if (rw == PCAN_READ_LTV) {
2394                 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_aplist),
2395                     AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
2396                         return (ret);
2397                 goto done;
2398         }
2399         PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
2400         PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
2401         PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
2402         PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
2403         if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_aplist),
2404             AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
2405                 return (ret);
2406 done:
2407         PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
2408         PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
2409         PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
2410         PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
2411         return (ret);
2412 }
2413 
2414 static uint16_t
2415 pcan_scanresult_ltv(int rw, pcan_maci_t *pcan_p, uint16_t type,
2416     struct an_ltv_scanresult *scanresult_p)
2417 {
2418         uint16_t ret, len;
2419         if (rw != PCAN_READ_LTV) {
2420                 cmn_err(CE_WARN, "pcan scan_ltv: readonly rid %x\n", type);
2421                 return (PCAN_FAIL);
2422         }
2423         if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_scanresult),
2424             type, (uint16_t *)scanresult_p))
2425                 return (ret);
2426         PCAN_SWAP16_BUF(scanresult_p->an_bssid);
2427         PCAN_SWAP16_BUF(scanresult_p->an_ssid);
2428         len = min(scanresult_p->an_ssidlen, 31);
2429         scanresult_p->an_ssid[len] = '\0';
2430         PCAN_SWAP16_BUF(scanresult_p->an_rates);
2431         return (PCAN_SUCCESS);
2432 }
2433 
2434 static uint16_t
2435 pcan_one_wepkey(int rw, pcan_maci_t *pcan_p, struct an_ltv_wepkey *wkp,
2436     uint16_t rid)
2437 {
2438         uint16_t ret;
2439 
2440         if (rw == PCAN_READ_LTV) {
2441                 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
2442                     rid, (uint16_t *)wkp)) {
2443                         return (ret);
2444                 }
2445                 goto done;
2446         }
2447         PCAN_SWAP16_BUF(wkp->an_macaddr);
2448         PCAN_SWAP16_BUF(wkp->an_key);
2449         if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
2450             rid, (uint16_t *)wkp))
2451                 return (ret);
2452 done:
2453         PCAN_SWAP16_BUF(wkp->an_macaddr);
2454         PCAN_SWAP16_BUF(wkp->an_key);
2455         return (ret);
2456 }
2457 
2458 static uint16_t
2459 pcan_wepkey_ltv(int rw, pcan_maci_t *pcan_p)
2460 {
2461         uint16_t ret, i;
2462         struct an_ltv_wepkey wk;
2463 
2464         if (rw == PCAN_READ_LTV) {
2465                 uint16_t rid = AN_RID_WEPKEY2;
2466 
2467                 if (ret = pcan_one_wepkey(rw, pcan_p, &wk, rid))
2468                         return (ret);
2469                 for (i = 0; i < 5; i++) {
2470                         if (wk.an_index < 4)
2471                                 pcan_p->an_wepkey[wk.an_index] = wk;
2472                         else if (wk.an_index == 0xffff)
2473                                 pcan_p->an_cur_wepkey = wk.an_macaddr[0];
2474                         rid = AN_RID_WEPKEY;
2475                 }
2476                 return (PCAN_SUCCESS);
2477         }
2478         for (i = 0; i < MAX_NWEPKEYS; i++) {
2479                 if (pcan_p->an_wepkey[i].an_index == i) {
2480                         if (ret = pcan_one_wepkey(rw, pcan_p,
2481                             &pcan_p->an_wepkey[i], AN_RID_WEPKEY2))
2482                                 return (ret);
2483                 }
2484         }
2485         /* Now set the default key */
2486         (void) memset(&wk, 0, sizeof (wk));
2487         wk.an_index = 0xffff;
2488         wk.an_macaddr[0] = pcan_p->an_cur_wepkey;
2489         ret = pcan_one_wepkey(rw, pcan_p, &wk, AN_RID_WEPKEY2);
2490         return (ret);
2491 }
2492 
2493 static uint16_t
2494 pcan_alloc_nicmem(pcan_maci_t *pcan_p, uint16_t len, uint16_t *id_p)
2495 {
2496         int i;
2497         uint16_t stat;
2498 
2499         len = ((len + 1) >> 1) << 1;        /* round up to 16-bit boundary */
2500 
2501         if (stat = pcan_set_cmd(pcan_p, AN_CMD_ALLOC_MEM, len))
2502                 return (stat);
2503         for (i = 0; !(stat & AN_EV_ALLOC) && (i < AN_TIMEOUT); i++) {
2504                 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
2505         }
2506         if (!(stat & AN_EV_ALLOC))
2507                 return (PCAN_TIMEDOUT_ALLOC);
2508         PCAN_READ(pcan_p, AN_ALLOC_FID, stat);
2509         PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
2510         *id_p = stat;
2511 
2512         /* zero fill the allocated NIC mem - sort of pcan_fill_ch0 */
2513         (void) pcan_set_ch(pcan_p, stat, 0, 0);
2514         for (len >>= 1, stat = 0; stat < len; stat++) {
2515                 PCAN_WRITE(pcan_p, AN_DATA0, 0);
2516         }
2517         return (PCAN_SUCCESS);
2518 }
2519 
2520 static void
2521 pcan_stop_rx_dma(pcan_maci_t *pcan_p)
2522 {
2523         int i, j;
2524         struct an_card_rx_desc  an_rx_desc;
2525 
2526         for (i = 0; i < AN_MAX_RX_DESC; i++) {
2527                 bzero(&an_rx_desc, sizeof (an_rx_desc));
2528                 an_rx_desc.an_valid = 0;
2529                 an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
2530                 an_rx_desc.an_done = 1;
2531                 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
2532                 for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
2533                         PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
2534                             + (i * sizeof (an_rx_desc))
2535                             + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
2536         }
2537 }
2538 
2539 static int
2540 pcan_init_dma_desc(pcan_maci_t *pcan_p)
2541 {
2542         int i, j;
2543         struct an_card_rid_desc an_rid_desc;
2544         struct an_card_rx_desc  an_rx_desc;
2545         struct an_card_tx_desc  an_tx_desc;
2546 
2547         /* Allocate DMA for rx */
2548         if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
2549             AN_DESCRIPTOR_RX, AN_RX_DESC_OFFSET,
2550             AN_MAX_RX_DESC) != PCAN_SUCCESS) {
2551                 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rx descriptor");
2552                 goto error;
2553         }
2554         for (i = 0; i < AN_MAX_RX_DESC; i++) {
2555                 bzero(&an_rx_desc, sizeof (an_rx_desc));
2556                 an_rx_desc.an_valid = 1;
2557                 an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
2558                 an_rx_desc.an_done = 0;
2559                 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
2560                 for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
2561                         PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
2562                             + (i * sizeof (an_rx_desc))
2563                             + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
2564         }
2565 
2566 
2567         /* Allocate DMA for tx */
2568         if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
2569             AN_DESCRIPTOR_TX, AN_TX_DESC_OFFSET,
2570             AN_MAX_TX_DESC) != PCAN_SUCCESS) {
2571                 cmn_err(CE_WARN, "pcan init_dma: fail to alloc tx descriptor");
2572                 goto error;
2573         }
2574 
2575         for (i = 0; i < AN_MAX_TX_DESC; i++) {
2576                 an_tx_desc.an_offset = 0;
2577                 an_tx_desc.an_eoc = 0;
2578                 an_tx_desc.an_valid = 0;
2579                 an_tx_desc.an_len = 0;
2580                 an_tx_desc.an_phys = pcan_p->pcan_tx[i].dma_physaddr;
2581 
2582                 for (j = 0; j < sizeof (an_tx_desc) / 4; j++)
2583                         PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET
2584                             + (i * sizeof (an_tx_desc))
2585                             + (j * 4), ((uint32_t *)&an_tx_desc)[j]);
2586         }
2587 
2588         /* Allocate DMA for rid */
2589         if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
2590             AN_DESCRIPTOR_HOSTRW, AN_HOST_DESC_OFFSET, 1) != PCAN_SUCCESS) {
2591                 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rid descriptor");
2592                 goto error;
2593         }
2594         bzero(&an_rid_desc, sizeof (an_rid_desc));
2595         an_rid_desc.an_valid = 1;
2596         an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
2597         an_rid_desc.an_rid = 0;
2598         an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
2599 
2600         for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
2601                 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
2602                     ((uint32_t *)&an_rid_desc)[i]);
2603 
2604         pcan_p->pcan_txring.an_tx_prod = 0;
2605         pcan_p->pcan_txring.an_tx_cons = 0;
2606         pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
2607         return (PCAN_SUCCESS);
2608 error:
2609         return (PCAN_FAIL);
2610 }
2611 
2612 static int
2613 pcan_init_dma(dev_info_t *dip, pcan_maci_t *pcan_p)
2614 {
2615         int i, ret = PCAN_FAIL;
2616         ddi_dma_cookie_t dma_cookie;
2617         size_t len;
2618 
2619         /* Allocate DMA for rx */
2620         for (i = 0; i < AN_MAX_RX_DESC; i++) {
2621                 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
2622                     DDI_DMA_SLEEP, 0,
2623                     &pcan_p->pcan_rx[i].dma_handle) != DDI_SUCCESS)
2624                         goto error;
2625 
2626                 if (ddi_dma_mem_alloc(pcan_p->pcan_rx[i].dma_handle,
2627                     AN_RX_BUFFER_SIZE, &accattr,
2628                     DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
2629                     (caddr_t *)&pcan_p->pcan_rx[i].dma_virtaddr, &len,
2630                     &pcan_p->pcan_rx[i].dma_acc_handle) != DDI_SUCCESS) {
2631                         goto error;
2632                 }
2633                 if (ddi_dma_addr_bind_handle(
2634                     pcan_p->pcan_rx[i].dma_handle,
2635                     NULL, (caddr_t)pcan_p->pcan_rx[i].dma_virtaddr,
2636                     len, DDI_DMA_READ |
2637                     DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
2638                     &pcan_p->pcan_rx[i].ncookies) != DDI_DMA_MAPPED) {
2639                         goto error;
2640                 }
2641                 ASSERT(pcan_p->pcan_rx[i].ncookies == 1);
2642                 pcan_p->pcan_rx[i].dma_physaddr = dma_cookie.dmac_address;
2643         }
2644 
2645         /* Allocate DMA for tx */
2646         for (i = 0; i < AN_MAX_TX_DESC; i++) {
2647                 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
2648                     DDI_DMA_SLEEP, 0,
2649                     &pcan_p->pcan_tx[i].dma_handle) != DDI_SUCCESS)
2650                         goto error;
2651 
2652                 if (ddi_dma_mem_alloc(pcan_p->pcan_tx[i].dma_handle,
2653                     AN_TX_BUFFER_SIZE, &accattr,
2654                     DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
2655                     (caddr_t *)&pcan_p->pcan_tx[i].dma_virtaddr, &len,
2656                     &pcan_p->pcan_tx[i].dma_acc_handle) != DDI_SUCCESS) {
2657                         goto error;
2658                 }
2659                 if (ddi_dma_addr_bind_handle(
2660                     pcan_p->pcan_tx[i].dma_handle,
2661                     NULL, (caddr_t)pcan_p->pcan_tx[i].dma_virtaddr,
2662                     len, DDI_DMA_WRITE |
2663                     DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
2664                     &pcan_p->pcan_tx[i].ncookies) != DDI_DMA_MAPPED) {
2665                         goto error;
2666                 }
2667                 ASSERT(pcan_p->pcan_tx[i].ncookies == 1);
2668                 pcan_p->pcan_tx[i].dma_physaddr = dma_cookie.dmac_address;
2669         }
2670 
2671         /* Allocate DMA for rid */
2672         if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
2673             DDI_DMA_SLEEP, 0,
2674             &pcan_p->pcan_cmd.dma_handle) != DDI_SUCCESS)
2675                 goto error;
2676 
2677         if (ddi_dma_mem_alloc(pcan_p->pcan_cmd.dma_handle,
2678             AN_RID_BUFFER_SIZE, &accattr,
2679             DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
2680             (caddr_t *)&pcan_p->pcan_cmd.dma_virtaddr, &len,
2681             &pcan_p->pcan_cmd.dma_acc_handle) != DDI_SUCCESS) {
2682                 goto error;
2683         }
2684         if (ddi_dma_addr_bind_handle(
2685             pcan_p->pcan_cmd.dma_handle,
2686             NULL, (caddr_t)pcan_p->pcan_cmd.dma_virtaddr,
2687             len, DDI_DMA_RDWR |
2688             DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, &dma_cookie,
2689             &pcan_p->pcan_cmd.ncookies) != DDI_DMA_MAPPED) {
2690                 goto error;
2691         }
2692         ASSERT(pcan_p->pcan_cmd.ncookies == 1);
2693         pcan_p->pcan_cmd.dma_physaddr = dma_cookie.dmac_address;
2694 
2695         if (ret = pcan_init_dma_desc(pcan_p)) {
2696                 cmn_err(CE_WARN, "pcan init_dma_desc: failed\n");
2697                 goto error;
2698         }
2699 
2700         return (PCAN_SUCCESS);
2701 error:
2702         pcan_free_dma(pcan_p);
2703         return (ret);
2704 }
2705 
2706 static void
2707 pcan_free_dma(pcan_maci_t *pcan_p)
2708 {
2709         int i;
2710 
2711         /* free RX dma */
2712         pcan_stop_rx_dma(pcan_p);
2713         for (i = 0; i < AN_MAX_RX_DESC; i++) {
2714                 if (pcan_p->pcan_rx[i].dma_handle != NULL) {
2715                         if (pcan_p->pcan_rx[i].ncookies) {
2716                                 (void) ddi_dma_unbind_handle(
2717                                     pcan_p->pcan_rx[i].dma_handle);
2718                                 pcan_p->pcan_rx[i].ncookies = 0;
2719                         }
2720                         ddi_dma_free_handle(
2721                             &pcan_p->pcan_rx[i].dma_handle);
2722                         pcan_p->pcan_rx[i].dma_handle = NULL;
2723                 }
2724                 if (pcan_p->pcan_rx[i].dma_acc_handle != NULL) {
2725                         ddi_dma_mem_free(
2726                             &pcan_p->pcan_rx[i].dma_acc_handle);
2727                         pcan_p->pcan_rx[i].dma_acc_handle = NULL;
2728                 }
2729         }
2730 
2731         /* free TX dma */
2732         for (i = 0; i < AN_MAX_TX_DESC; i++) {
2733                 if (pcan_p->pcan_tx[i].dma_handle != NULL) {
2734                         if (pcan_p->pcan_tx[i].ncookies) {
2735                                 (void) ddi_dma_unbind_handle(
2736                                     pcan_p->pcan_tx[i].dma_handle);
2737                                 pcan_p->pcan_tx[i].ncookies = 0;
2738                         }
2739                         ddi_dma_free_handle(
2740                             &pcan_p->pcan_tx[i].dma_handle);
2741                         pcan_p->pcan_tx[i].dma_handle = NULL;
2742                 }
2743                 if (pcan_p->pcan_tx[i].dma_acc_handle != NULL) {
2744                         ddi_dma_mem_free(
2745                             &pcan_p->pcan_tx[i].dma_acc_handle);
2746                         pcan_p->pcan_tx[i].dma_acc_handle = NULL;
2747                 }
2748         }
2749 
2750         /* free cmd dma */
2751         if (pcan_p->pcan_cmd.dma_handle != NULL) {
2752                 if (pcan_p->pcan_cmd.ncookies) {
2753                         (void) ddi_dma_unbind_handle(
2754                             pcan_p->pcan_cmd.dma_handle);
2755                         pcan_p->pcan_cmd.ncookies = 0;
2756                 }
2757                 ddi_dma_free_handle(
2758                     &pcan_p->pcan_cmd.dma_handle);
2759                 pcan_p->pcan_cmd.dma_handle = NULL;
2760         }
2761         if (pcan_p->pcan_cmd.dma_acc_handle != NULL) {
2762                 ddi_dma_mem_free(
2763                     &pcan_p->pcan_cmd.dma_acc_handle);
2764                 pcan_p->pcan_cmd.dma_acc_handle = NULL;
2765         }
2766 }
2767 
2768 /*
2769  * get card capability (WEP, default channel), setup broadcast, mac addresses
2770  */
2771 static uint32_t
2772 pcan_get_cap(pcan_maci_t *pcan_p)
2773 {
2774         uint16_t stat;
2775 
2776         if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_config)) {
2777                 PCANDBG((CE_NOTE, "pcan get_cap: read cfg fail %x", stat));
2778                 return ((uint32_t)AN_RID_GENCONFIG << 16 | stat);
2779         }
2780 
2781         if (stat = pcan_cap_ltv(PCAN_READ_LTV, pcan_p)) {
2782                 PCANDBG((CE_NOTE, "pcan get_cap: read cap fail %x", stat));
2783                 return ((uint32_t)AN_RID_CAPABILITIES << 16 | stat);
2784         }
2785 #ifdef DEBUG
2786         if (pcan_debug & PCAN_DBG_FW_VERSION) {
2787                 cmn_err(CE_NOTE, "the version of the firmware in the wifi card "
2788                     "'%s %s %s' is %s\n",
2789                     pcan_p->an_caps.an_manufname,
2790                     pcan_p->an_caps.an_prodname,
2791                     pcan_p->pcan_device_type == PCAN_DEVICE_PCI ?
2792                     "minipci" : "pccard",
2793                     pcan_p->an_caps.an_prodvers);
2794         }
2795 #endif
2796 
2797         if (stat = pcan_ssid_ltv(PCAN_READ_LTV, pcan_p)) {
2798                 PCANDBG((CE_NOTE, "pcan get_cap: read ssid fail %x", stat));
2799                 return ((uint32_t)AN_RID_SSIDLIST << 16 | stat);
2800         }
2801 
2802         if (stat = pcan_aplist_ltv(PCAN_READ_LTV, pcan_p)) {
2803                 PCANDBG((CE_NOTE, "pcan get_cap: read aplist fail %x", stat));
2804                 return ((uint32_t)AN_RID_APLIST << 16 | stat);
2805         }
2806         if (stat = pcan_wepkey_ltv(PCAN_READ_LTV, pcan_p)) {
2807                 PCANDBG((CE_NOTE, "pcan get_cap: read wepkey fail %x", stat));
2808                 return ((uint32_t)AN_RID_WEPKEY2 << 16 | stat);
2809         }
2810         ether_copy(pcan_p->an_caps.an_oemaddr, pcan_p->pcan_mac_addr);
2811         return (PCAN_SUCCESS);
2812 }
2813 
2814 static int
2815 pcan_config_mac(pcan_maci_t *pcan_p)
2816 {
2817         uint16_t stat;
2818 
2819         if (stat = pcan_ssid_ltv(PCAN_WRITE_LTV, pcan_p)) {
2820                 PCANDBG((CE_NOTE, "pcan config_mac: write SSID failed%x\n",
2821                     stat));
2822                 return ((int)stat);
2823         }
2824 
2825         if (stat = pcan_aplist_ltv(PCAN_WRITE_LTV, pcan_p)) {
2826                 PCANDBG((CE_NOTE, "pcan config_mac: write APlist failed%x\n",
2827                     stat));
2828                 return ((int)stat);
2829         }
2830         if (stat = pcan_wepkey_ltv(PCAN_WRITE_LTV, pcan_p)) {
2831                 PCANDBG((CE_NOTE, "pcan config_mac: write wepkey failed%x\n",
2832                     stat));
2833                 return ((int)stat);
2834         }
2835         if (pcan_p->pcan_usewep)
2836                 pcan_p->an_config.an_authtype |=
2837                     AN_AUTHTYPE_ENABLEWEP | AN_AUTHTYPE_ALLOW_UNENCRYPTED;
2838         PCANDBG((CE_NOTE, "pcan config_mac: usewep=%x authtype=%x opmode=%x\n",
2839             pcan_p->pcan_usewep, pcan_p->an_config.an_authtype,
2840             pcan_p->an_config.an_opmode));
2841 
2842         pcan_p->an_config.an_assoc_timeout = 5000; /* stop assoc seq in 5 sec */
2843         if (stat = pcan_cfg_ltv(PCAN_WRITE_LTV, pcan_p, &pcan_p->an_config)) {
2844                 PCANDBG((CE_NOTE, "pcan config_mac: write cfg failed %x\n",
2845                     stat));
2846                 return ((int)stat);
2847         }
2848 
2849         if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p,
2850             &pcan_p->an_actual_config)) {
2851                 PCANDBG((CE_NOTE, "pcan config_mac: read cfg failed%x\n",
2852                     stat));
2853                 return ((int)stat);
2854         }
2855         PCANDBG((CE_NOTE, "pcan config_mac: optionmask=%x authtype=%x\n", 0,
2856             pcan_p->an_actual_config.an_authtype));
2857 
2858         if (stat = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
2859                 PCANDBG((CE_NOTE, "pcan config_mac: read status failed %x\n",
2860                     stat));
2861                 return ((int)stat);
2862         }
2863         return (PCAN_SUCCESS);
2864 }
2865 
2866 static int
2867 pcan_loaddef(pcan_maci_t *pcan_p)
2868 {
2869         int i;
2870 
2871         pcan_p->an_ssidlist.an_ssid1_len = 0;
2872         bzero(pcan_p->an_ssidlist.an_ssid1,
2873             sizeof (pcan_p->an_ssidlist.an_ssid1));
2874         for (i = 0; i < MAX_NWEPKEYS; i++) {
2875                 pcan_p->an_wepkey[i].an_index = 0xffff;
2876                 bzero(pcan_p->an_wepkey[i].an_key,
2877                     sizeof (pcan_p->an_wepkey[i].an_key));
2878                 pcan_p->an_wepkey[i].an_keylen = 0;
2879                 bzero(pcan_p->an_wepkey[i].an_macaddr,
2880                     sizeof (pcan_p->an_wepkey[i].an_macaddr));
2881                 pcan_p->an_wepkey[i].an_macaddr[0] = 1;
2882         }
2883         pcan_p->an_cur_wepkey = 0;
2884 
2885         pcan_p->pcan_usewep = 0;
2886         pcan_p->an_config.an_opmode = AN_OPMODE_INFR_STATION;
2887         pcan_p->an_config.an_authtype = AN_AUTHTYPE_OPEN;
2888         pcan_p->an_config.an_stationary = 1;
2889         pcan_p->an_config.an_max_beacon_lost_time = 0xffff;
2890         i = pcan_config_mac(pcan_p);
2891 
2892         return (i);
2893 }
2894 
2895 static int
2896 pcan_init_nicmem(pcan_maci_t *pcan_p)
2897 {
2898         int i;
2899         uint16_t ret;
2900         pcan_txring_t *ring_p = &pcan_p->pcan_txring;
2901 
2902         for (i = 0; i < AN_TX_RING_CNT; i++) {
2903                 uint16_t rc;
2904                 ret = pcan_alloc_nicmem(pcan_p, PCAN_NICMEM_SZ, &rc);
2905                 if (ret) {
2906                         cmn_err(CE_WARN, "pcan alloc NIC Tx buf[%x]: failed "
2907                             "%x\n", i, ret);
2908                         return (DDI_FAILURE);
2909                 }
2910                 ring_p->an_tx_fids[i] = rc;
2911                 ring_p->an_tx_ring[i] = 0;
2912                 PCANDBG((CE_NOTE, "pcan: NIC tx_id[%x]=%x\n", i, rc));
2913         }
2914         ring_p->an_tx_prod = ring_p->an_tx_cons = 0;
2915         return (PCAN_SUCCESS);
2916 }
2917 
2918 
2919 
2920 static void
2921 pcan_start_locked(pcan_maci_t *pcan_p)
2922 {
2923         pcan_p->pcan_flag |= PCAN_CARD_INTREN;
2924         PCAN_ENABLE_INTR(pcan_p);
2925 }
2926 
2927 static void
2928 pcan_stop_locked(pcan_maci_t *pcan_p)
2929 {
2930         PCAN_DISABLE_INTR_CLEAR(pcan_p);
2931         pcan_p->pcan_flag &= ~PCAN_CARD_INTREN;
2932 }
2933 
2934 /*
2935  * for scan result
2936  */
2937 static int
2938 pcan_add_scan_item(pcan_maci_t *pcan_p, struct an_ltv_scanresult s)
2939 {
2940         an_scan_list_t *scan_item;
2941 
2942         scan_item = kmem_zalloc(sizeof (an_scan_list_t), KM_SLEEP);
2943         if (scan_item == NULL) {
2944                 cmn_err(CE_WARN, "pcan add_scan_item: zalloc failed\n");
2945                 return (PCAN_FAIL);
2946         }
2947         scan_item->an_val = s;
2948         scan_item->an_timeout = AN_SCAN_TIMEOUT_MAX;
2949         list_insert_tail(&pcan_p->an_scan_list, scan_item);
2950         pcan_p->an_scan_num++;
2951         return (PCAN_SUCCESS);
2952 }
2953 
2954 static void
2955 pcan_delete_scan_item(pcan_maci_t *pcan_p, an_scan_list_t *s)
2956 {
2957         list_remove(&pcan_p->an_scan_list, s);
2958         kmem_free(s, sizeof (*s));
2959         pcan_p->an_scan_num--;
2960 }
2961 
2962 static void
2963 pcan_scanlist_timeout(void *arg)
2964 {
2965         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
2966         an_scan_list_t *scan_item0, *scan_item1;
2967 
2968         mutex_enter(&pcan_p->pcan_scanlist_lock);
2969         scan_item0 = list_head(&pcan_p->an_scan_list);
2970         for (; scan_item0; ) {
2971                 PCANDBG((CE_NOTE, "pcan scanlist: ssid = %s\n",
2972                     scan_item0->an_val.an_ssid));
2973                 PCANDBG((CE_NOTE, "pcan scanlist: timeout left: %ds",
2974                     scan_item0->an_timeout));
2975                 scan_item1 = list_next(&pcan_p->an_scan_list, scan_item0);
2976                 if (scan_item0->an_timeout == 0) {
2977                         pcan_delete_scan_item(pcan_p, scan_item0);
2978                 } else {
2979                         scan_item0->an_timeout--;
2980                 }
2981                 scan_item0 = scan_item1;
2982         }
2983         mutex_exit(&pcan_p->pcan_scanlist_lock);
2984         pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
2985             pcan_p, drv_usectohz(1000000));
2986 }
2987 
2988 /*
2989  * Brussels support
2990  */
2991 /*
2992  * MAC_PROP_WL_ESSID
2993  */
2994 static int
2995 pcan_set_essid(pcan_maci_t *pcan_p, const void *wldp_buf)
2996 {
2997         char *value;
2998         struct an_ltv_ssidlist  *ssidlist_p;
2999         wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf;
3000 
3001         ssidlist_p = &pcan_p->an_ssidlist;
3002         bzero(ssidlist_p, sizeof (*ssidlist_p));
3003         value = iw_essid->wl_essid_essid;
3004         (void) strncpy(ssidlist_p->an_ssid1, value,
3005             MIN(32, strlen(value)));
3006         ssidlist_p->an_ssid1_len = strlen(value);
3007 
3008         return (ENETRESET);
3009 }
3010 
3011 static int
3012 pcan_get_essid(pcan_maci_t *pcan_p, void *wldp_buf)
3013 {
3014         int err = 0;
3015         struct an_ltv_status *status_p;
3016         wl_essid_t *ow_essid = (wl_essid_t *)wldp_buf;
3017 
3018         status_p = &pcan_p->an_status;
3019 
3020         if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3021                 err = EIO;
3022                 return (err);
3023         }
3024         ow_essid->wl_essid_length = status_p->an_ssidlen;
3025         bcopy(status_p->an_ssid, ow_essid->wl_essid_essid,
3026             status_p->an_ssidlen);
3027 
3028         return (err);
3029 }
3030 
3031 /*
3032  * MAC_PROP_WL_BSSID
3033  */
3034 static int
3035 pcan_set_bssid(pcan_maci_t *pcan_p, const void *wldp_buf)
3036 {
3037         wl_bssid_t *value;
3038         struct an_ltv_aplist *aplist_p;
3039 
3040         aplist_p = &pcan_p->an_aplist;
3041 
3042         value = (wl_bssid_t *)wldp_buf;
3043         (void) strncpy((char *)aplist_p->an_ap1, (char *)value, 6);
3044 
3045         return (ENETRESET);
3046 }
3047 
3048 static int
3049 pcan_get_bssid(pcan_maci_t *pcan_p, void *wldp_buf)
3050 {
3051         int     err = 0;
3052         struct  an_ltv_status *status_p;
3053 
3054         status_p = &pcan_p->an_status;
3055 
3056         if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3057                 err = EIO;
3058                 return (err);
3059         }
3060 
3061         bcopy(status_p->an_cur_bssid, wldp_buf, sizeof (wl_bssid_t));
3062         PCANDBG((CE_CONT,
3063             "pcan: cfg_bssid: bssid=%x %x %x %x %x %x\n",
3064             status_p->an_cur_bssid[0],
3065             status_p->an_cur_bssid[1],
3066             status_p->an_cur_bssid[2],
3067             status_p->an_cur_bssid[3],
3068             status_p->an_cur_bssid[4],
3069             status_p->an_cur_bssid[5]));
3070 
3071         return (err);
3072 }
3073 
3074 /*
3075  * MAC_PROP_WL_LINKSTATUS
3076  */
3077 static void
3078 pcan_get_linkstatus(pcan_maci_t *pcan_p, void *wldp_buf)
3079 {
3080         if (pcan_p->pcan_flag & PCAN_CARD_LINKUP)
3081                 *(wl_linkstatus_t *)wldp_buf = WL_CONNECTED;
3082         else
3083                 *(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED;
3084 
3085 }
3086 
3087 /*
3088  * MAC_PROP_WL_BSSTYP
3089  */
3090 static int
3091 pcan_set_bsstype(pcan_maci_t *pcan_p, const void *wldp_buf)
3092 {
3093         struct an_ltv_genconfig *cfg_p;
3094 
3095         cfg_p = &pcan_p->an_config;
3096 
3097         if (*(wl_bss_type_t *)wldp_buf == WL_BSS_BSS)
3098                 cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
3099         if (*(wl_bss_type_t *)wldp_buf == WL_BSS_IBSS)
3100                 cfg_p->an_opmode = AN_OPMODE_IBSS_ADHOC;
3101         if (*(wl_bss_type_t *)wldp_buf == WL_BSS_ANY)
3102                 cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
3103         cfg_p->an_assoc_timeout = 5000;
3104 
3105         return (ENETRESET);
3106 }
3107 
3108 static void
3109 pcan_get_bsstype(pcan_maci_t *pcan_p, void *wldp_buf)
3110 {
3111         struct an_ltv_genconfig *cfg_p;
3112 
3113         cfg_p = &pcan_p->an_config;
3114 
3115         if (cfg_p->an_opmode == AN_OPMODE_INFR_STATION) {
3116                 *(wl_bss_type_t *)wldp_buf = WL_BSS_BSS;
3117         } else if (cfg_p->an_opmode == AN_OPMODE_IBSS_ADHOC) {
3118                 *(wl_bss_type_t *)wldp_buf = WL_BSS_IBSS;
3119         }
3120 }
3121 
3122 /*
3123  * MAC_PROP_WL_PHY_CONFIG
3124  */
3125 static int
3126 pcan_set_phy(pcan_maci_t *pcan_p, const void *wldp_buf)
3127 {
3128         uint16_t ret;
3129         int err = ENETRESET;
3130         wl_phy_conf_t *phy = (wl_phy_conf_t *)wldp_buf;
3131         struct an_ltv_genconfig *cfg_p;
3132 
3133         cfg_p = &pcan_p->an_config;
3134 
3135         ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel);
3136         if (ret < 1 || ret > 14) {
3137                 err = ENOTSUP;
3138                 return (err);
3139         }
3140         cfg_p->an_ds_channel = ret;
3141         cfg_p->an_assoc_timeout = 5000;
3142 
3143         return (err);
3144 }
3145 
3146 static int
3147 pcan_get_phy(pcan_maci_t *pcan_p, void *wldp_buf)
3148 {
3149         int err = 0;
3150         struct an_ltv_status *status_p;
3151         wl_dsss_t *dsss = (wl_dsss_t *)wldp_buf;
3152 
3153         status_p = &pcan_p->an_status;
3154 
3155         if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3156                 err = EIO;
3157                 return (err);
3158         }
3159 
3160         dsss->wl_dsss_channel = status_p->an_channel_set;
3161         dsss->wl_dsss_subtype = WL_DSSS;
3162 
3163         return (err);
3164 }
3165 
3166 /*
3167  * MAC_PROP_WL_DESIRED_RATESa
3168  */
3169 static int
3170 pcan_set_desrates(pcan_maci_t *pcan_p, const void *wldp_buf)
3171 {
3172         uint16_t i;
3173         struct an_ltv_genconfig *cfg_p;
3174 
3175         cfg_p = &pcan_p->an_config;
3176 
3177         bzero(cfg_p->an_rates, sizeof (cfg_p->an_rates));
3178         for (i = 0; i < ((wl_rates_t *)wldp_buf)->wl_rates_num; i++) {
3179                 cfg_p->an_rates[i] =
3180                     (((wl_rates_t *)wldp_buf)->wl_rates_rates)[i];
3181         }
3182         cfg_p->an_assoc_timeout = 5000;
3183 
3184         return (ENETRESET);
3185 }
3186 
3187 static int
3188 pcan_get_desrates(pcan_maci_t *pcan_p, void *wldp_buf)
3189 {
3190         uint16_t i;
3191         uint8_t rates = 0;
3192         int     err = 0;
3193         struct an_ltv_genconfig *actcfg_p;
3194 
3195         actcfg_p = &pcan_p->an_actual_config;
3196 
3197         if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
3198                 err = EIO;
3199                 return (err);
3200         }
3201 
3202         for (i = 0; i < sizeof (actcfg_p->an_rates); i++) {
3203                 if (actcfg_p->an_rates[i] == 0)
3204                         break;
3205                 rates = MAX(rates, actcfg_p->an_rates[i]);
3206         }
3207         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = rates;
3208         ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
3209 
3210         return (err);
3211 }
3212 
3213 /*
3214  * MAC_PROP_WL_SUP_RATE
3215  */
3216 static void
3217 pcan_get_suprates(void *wldp_buf)
3218 {
3219         wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf;
3220 
3221         wl_rates->wl_rates_num = 4;
3222         wl_rates->wl_rates_rates[0] = WL_RATE_1M;
3223         wl_rates->wl_rates_rates[1] = WL_RATE_2M;
3224         wl_rates->wl_rates_rates[2] = WL_RATE_5_5M;
3225         wl_rates->wl_rates_rates[3] = WL_RATE_11M;
3226 }
3227 
3228 /*
3229  * MAC_PROP_WL_POWER_MODE
3230  */
3231 static int
3232 pcan_get_powermode(pcan_maci_t *pcan_p, void *wldp_buf)
3233 {
3234         int err = 0;
3235         wl_ps_mode_t *powermode = (wl_ps_mode_t *)wldp_buf;
3236         struct an_ltv_genconfig *actcfg_p;
3237 
3238         actcfg_p = &pcan_p->an_actual_config;
3239         if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
3240                 err = EIO;
3241                 return (err);
3242         }
3243         powermode->wl_ps_mode = actcfg_p->an_psave_mode;
3244 
3245         return (err);
3246 }
3247 
3248 /*
3249  * MAC_PROP_AUTH_MODE
3250  */
3251 static int
3252 pcan_set_authmode(pcan_maci_t *pcan_p, const void *wldp_buf)
3253 {
3254         struct an_ltv_genconfig *cfg_p;
3255         int err = ENETRESET;
3256 
3257         cfg_p = &pcan_p->an_config;
3258         if (*(wl_authmode_t *)wldp_buf == WL_OPENSYSTEM) {
3259                 cfg_p->an_authtype |= AN_AUTHTYPE_OPEN;
3260                 cfg_p->an_assoc_timeout = 5000;
3261         } else {
3262                 err = EINVAL;
3263         }
3264 
3265         return (err);
3266 }
3267 
3268 static void
3269 pcan_get_authmode(pcan_maci_t *pcan_p, void *wldp_buf)
3270 {
3271         struct an_ltv_genconfig *cfg_p;
3272 
3273         cfg_p = &pcan_p->an_config;
3274         if (cfg_p->an_authtype & AN_AUTHTYPE_SHAREDKEY) {
3275                 *(wl_bss_type_t *)wldp_buf = WL_SHAREDKEY;
3276         } else {
3277                 *(wl_bss_type_t *)wldp_buf = WL_OPENSYSTEM;
3278         }
3279 }
3280 
3281 /*
3282  * MAC_PROP_WL_ENCRYPTION
3283  */
3284 static int
3285 pcan_set_encrypt(pcan_maci_t *pcan_p, const void *wldp_buf)
3286 {
3287         struct an_ltv_genconfig *cfg_p;
3288 
3289         cfg_p = &pcan_p->an_config;
3290         if (*(wl_encryption_t *)wldp_buf == WL_ENC_WEP) {
3291                 cfg_p->an_authtype |= (AN_AUTHTYPE_ENABLEWEP |
3292                     AN_AUTHTYPE_ALLOW_UNENCRYPTED);
3293                 pcan_p->pcan_usewep = 1;
3294         }
3295         if (*(wl_authmode_t *)wldp_buf == WL_NOENCRYPTION) {
3296                 cfg_p->an_authtype &= (~(AN_AUTHTYPE_ENABLEWEP |
3297                     AN_AUTHTYPE_ALLOW_UNENCRYPTED));
3298                 pcan_p->pcan_usewep = 0;
3299         }
3300         cfg_p->an_assoc_timeout = 5000;
3301 
3302         return (ENETRESET);
3303 }
3304 
3305 static void
3306 pcan_get_encrypt(pcan_maci_t *pcan_p, void *wldp_buf)
3307 {
3308         struct an_ltv_genconfig *cfg_p;
3309 
3310         cfg_p = &pcan_p->an_config;
3311         if (cfg_p->an_authtype & AN_AUTHTYPE_ENABLEWEP) {
3312                 *(wl_bss_type_t *)wldp_buf = WL_ENC_WEP;
3313         } else {
3314                 *(wl_bss_type_t *)wldp_buf = WL_NOENCRYPTION;
3315         }
3316 }
3317 
3318 /*
3319  * MAC_PROP_WL_KEY_TAB
3320  */
3321 static int
3322 pcan_set_wepkey(pcan_maci_t *pcan_p, const void *wldp_buf)
3323 {
3324         uint16_t i;
3325         wl_wep_key_t *p_wepkey_tab;
3326         struct an_ltv_wepkey *wepkey_p;
3327 
3328         p_wepkey_tab = (wl_wep_key_t *)wldp_buf;
3329         for (i = 0; i < MAX_NWEPKEYS; i++) {
3330                 if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) {
3331                         wepkey_p = &pcan_p->an_wepkey[i];
3332                         bzero(wepkey_p, sizeof (*wepkey_p));
3333                         wepkey_p->an_keylen =
3334                             p_wepkey_tab[i].wl_wep_length;
3335                         bcopy(p_wepkey_tab[i].wl_wep_key,
3336                             wepkey_p->an_key,
3337                             p_wepkey_tab[i].wl_wep_length);
3338                         wepkey_p->an_index = i;
3339                         wepkey_p->an_macaddr[0] = 1;
3340                 }
3341         }
3342 
3343         return (ENETRESET);
3344 }
3345 
3346 /*
3347  * MAC_PROP_WL_RSSI
3348  */
3349 static int
3350 pcan_get_rssi(pcan_maci_t *pcan_p, void *wldp_buf)
3351 {
3352         uint16_t val;
3353         int err = 0;
3354         wl_rssi_t *rssi = (wl_rssi_t *)wldp_buf;
3355         struct an_ltv_status *status_p;
3356 
3357         status_p = &pcan_p->an_status;
3358 
3359         if (val = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3360                 err = EIO;
3361                 return (err);
3362         }
3363         val = status_p->an_cur_signal_quality;
3364         PCANDBG((CE_NOTE, "pcan cfg_rssi: sl=%x", val));
3365         /*
3366          * we reflect the value to 1-15 as rssi
3367          */
3368         *rssi = 15 - ((val & 0xff) * 15 / 128 + 1);
3369 
3370         return (err);
3371 }
3372 
3373 /*
3374  * MAC_PROP_WL_RADIO
3375  */
3376 static void
3377 pcan_get_radio(void *wldp_buf)
3378 {
3379         wl_radio_t *radio = (wl_radio_t *)wldp_buf;
3380 
3381         *radio = B_TRUE;
3382 }
3383 
3384 /*
3385  * MAC_PROP_WL_ESSLIST
3386  */
3387 static void
3388 pcan_get_esslist(pcan_maci_t *pcan_p, void *wldp_buf)
3389 {
3390         uint16_t        i;
3391         wl_ess_conf_t   *p_ess_conf;
3392         an_scan_list_t  *scan_item;
3393 
3394         mutex_enter(&pcan_p->pcan_scanlist_lock);
3395 
3396         ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
3397             pcan_p->an_scan_num;
3398         scan_item = list_head(&pcan_p->an_scan_list);
3399         for (i = 0; i < pcan_p->an_scan_num; i++) {
3400                 if (!scan_item)
3401                         break;
3402                 p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
3403                     offsetof(wl_ess_list_t, wl_ess_list_ess) +
3404                     i * sizeof (wl_ess_conf_t));
3405                 bcopy(scan_item->an_val.an_ssid,
3406                     p_ess_conf->wl_ess_conf_essid.wl_essid_essid,
3407                     mi_strlen(scan_item->an_val.an_ssid));
3408                 bcopy(scan_item->an_val.an_bssid,
3409                     p_ess_conf->wl_ess_conf_bssid, 6);
3410                 (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype
3411                     = WL_DSSS;
3412                 p_ess_conf->wl_ess_conf_wepenabled =
3413                     (scan_item->an_val.an_cap & 0x10 ?
3414                     WL_ENC_WEP : WL_NOENCRYPTION);
3415                 p_ess_conf->wl_ess_conf_bsstype =
3416                     (scan_item->an_val.an_cap & 0x1 ?
3417                     WL_BSS_BSS : WL_BSS_IBSS);
3418                 p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel =
3419                     scan_item->an_val.an_dschannel;
3420                 p_ess_conf->wl_ess_conf_sl = 15 -
3421                     ((scan_item->an_val.an_rssi & 0xff) * 15 / 128);
3422                 p_ess_conf->wl_supported_rates[0] = WL_RATE_1M;
3423                 p_ess_conf->wl_supported_rates[1] = WL_RATE_2M;
3424                 p_ess_conf->wl_supported_rates[2] = WL_RATE_5_5M;
3425                 p_ess_conf->wl_supported_rates[3] = WL_RATE_11M;
3426                 scan_item = list_next(&pcan_p->an_scan_list, scan_item);
3427         }
3428 
3429         mutex_exit(&pcan_p->pcan_scanlist_lock);
3430 }
3431 
3432 /*
3433  * for wificonfig and dlamd ioctl
3434  */
3435 static int
3436 pcan_cfg_essid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3437 {
3438         uint16_t                i;
3439         wldp_t                  *infp;
3440         wldp_t                  *outfp;
3441         char                    *buf;
3442         int                     iret;
3443         int                     err = 0;
3444 
3445         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3446         if (buf == NULL) {
3447                 PCANDBG((CE_NOTE, "pcan cfg_essid: failed to alloc "
3448                     "memory(%d)\n", MAX_BUF_LEN));
3449                 return (ENOMEM);
3450         }
3451         outfp = (wldp_t *)buf;
3452         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3453         infp = (wldp_t *)mp->b_rptr;
3454 
3455         if (cmd == WLAN_GET_PARAM) {
3456                 err = pcan_get_essid(pcan_p, outfp->wldp_buf);
3457                 if (err == EIO) {
3458                         outfp->wldp_length = WIFI_BUF_OFFSET;
3459                         outfp->wldp_result = WL_HW_ERROR;
3460                         goto done;
3461                 }
3462                 outfp->wldp_result = WL_SUCCESS;
3463         } else if (cmd == WLAN_SET_PARAM) {
3464                 (void) pcan_set_essid(pcan_p, infp->wldp_buf);
3465                 outfp->wldp_length = WIFI_BUF_OFFSET;
3466                 outfp->wldp_result = WL_SUCCESS;
3467         } else {
3468                 kmem_free(buf, MAX_BUF_LEN);
3469                 return (EINVAL);
3470         }
3471 
3472 done:
3473         for (i = 0; i < (outfp->wldp_length); i++) {
3474                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3475         }
3476         iret = (int)(outfp->wldp_result);
3477         kmem_free(buf, MAX_BUF_LEN);
3478         return (iret);
3479 }
3480 
3481 static int
3482 pcan_cfg_bssid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3483 {
3484         uint16_t        i;
3485         wldp_t          *infp;
3486         wldp_t          *outfp;
3487         char            *buf;
3488         int             iret;
3489         int             err = 0;
3490 
3491         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3492         if (buf == NULL) {
3493                 PCANDBG((CE_NOTE, "pcan cfg_bssid: failed to alloc "
3494                     "memory(%d)\n", MAX_BUF_LEN));
3495                 return (ENOMEM);
3496         }
3497         outfp = (wldp_t *)buf;
3498         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3499         infp = (wldp_t *)mp->b_rptr;
3500 
3501         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t);
3502 
3503         if (cmd == WLAN_GET_PARAM) {
3504                 err = pcan_get_bssid(pcan_p, outfp->wldp_buf);
3505                 if (err == EIO) {
3506                         outfp->wldp_length = WIFI_BUF_OFFSET;
3507                         outfp->wldp_result = WL_HW_ERROR;
3508                         goto done;
3509                 }
3510                 outfp->wldp_result = WL_SUCCESS;
3511         } else if (cmd == WLAN_SET_PARAM) {
3512                 (void) pcan_set_bssid(pcan_p, infp->wldp_buf);
3513                 outfp->wldp_length = WIFI_BUF_OFFSET;
3514                 outfp->wldp_result = WL_SUCCESS;
3515         } else {
3516                 kmem_free(buf, MAX_BUF_LEN);
3517                 return (EINVAL);
3518         }
3519 
3520 done:
3521         for (i = 0; i < (outfp->wldp_length); i++) {
3522                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3523         }
3524         iret = (int)(outfp->wldp_result);
3525         kmem_free(buf, MAX_BUF_LEN);
3526         return (iret);
3527 }
3528 
3529 /*ARGSUSED*/
3530 static int
3531 pcan_cmd_scan(pcan_maci_t *pcan_p)
3532 {
3533         uint16_t i = 0, j, ret = WL_SUCCESS;
3534         uint8_t bssid_t[6];
3535         uint32_t check_num, enable;
3536         an_scan_list_t *scan_item0;
3537 
3538         enable = pcan_p->pcan_flag & PCAN_ENABLED;
3539         if ((!enable) &&
3540             (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0))) {
3541                 ret = (int)WL_HW_ERROR;
3542                 goto exit;
3543         }
3544         if (ret = pcan_set_cmd(pcan_p, AN_CMD_SCAN, 0)) {
3545                 ret = (int)WL_HW_ERROR;
3546                 goto exit;
3547         }
3548 
3549         pcan_delay(pcan_p, 500000);
3550         ret =  pcan_scanresult_ltv(PCAN_READ_LTV,
3551             pcan_p, AN_RID_ESSIDLIST_FIRST, &pcan_p->an_scanresult[i]);
3552         if ((ret) || pcan_p->an_scanresult[i].an_index == 0xffff) {
3553                 goto done;
3554         }
3555         do
3556         {
3557                 i++;
3558                 ret =  pcan_scanresult_ltv(PCAN_READ_LTV,
3559                     pcan_p, AN_RID_ESSIDLIST_NEXT, &pcan_p->an_scanresult[i]);
3560         } while ((!ret) && (i < 32) &&
3561             (pcan_p->an_scanresult[i].an_index != 0xffff));
3562 done:
3563         if ((!enable) &&
3564             (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))) {
3565                 ret = (int)WL_HW_ERROR;
3566                 goto exit;
3567         }
3568         /* record the scan result for future use */
3569         bzero(bssid_t, sizeof (bssid_t));
3570         for (j = 0; j < i; j++) {
3571                 /*
3572                  * sometimes, those empty items are recorded by hardware,
3573                  * this is wrong, just ignore those items here.
3574                  */
3575                 if (bcmp(pcan_p->an_scanresult[j].an_bssid,
3576                     bssid_t, 6) == 0) {
3577                         continue;
3578                 }
3579                 /*
3580                  * save/update the scan item in scanlist
3581                  */
3582                 mutex_enter(&pcan_p->pcan_scanlist_lock);
3583                 check_num = 0;
3584                 scan_item0 = list_head(&pcan_p->an_scan_list);
3585                 if (scan_item0 == NULL) {
3586                         if (pcan_add_scan_item(pcan_p,
3587                             pcan_p->an_scanresult[j]) != 0) {
3588                                 mutex_exit(&pcan_p->pcan_scanlist_lock);
3589                                 return (WL_SUCCESS);
3590                         }
3591                 }
3592                 for (; scan_item0; ) {
3593                         if (bcmp(pcan_p->an_scanresult[j].an_bssid,
3594                             scan_item0->an_val.an_bssid, 6) == 0) {
3595                                 scan_item0->an_val = pcan_p->an_scanresult[j];
3596                                 scan_item0->an_timeout = AN_SCAN_TIMEOUT_MAX;
3597                                 break;
3598                         } else {
3599                                 check_num++;
3600                         }
3601                         scan_item0 = list_next(&pcan_p->an_scan_list,
3602                             scan_item0);
3603                 }
3604                 if (check_num == pcan_p->an_scan_num) {
3605                         if (pcan_add_scan_item(pcan_p,
3606                             pcan_p->an_scanresult[j]) != 0) {
3607                                 mutex_exit(&pcan_p->pcan_scanlist_lock);
3608                                 return (WL_SUCCESS);
3609                         }
3610                 }
3611                 mutex_exit(&pcan_p->pcan_scanlist_lock);
3612         }
3613 exit:
3614         if (ret)
3615                 cmn_err(CE_WARN, "pcan: scan failed due to hardware error");
3616         return (ret);
3617 }
3618 
3619 /*ARGSUSED*/
3620 static int
3621 pcan_cfg_scan(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3622 {
3623         wldp_t          *outfp;
3624         char            *buf;
3625         uint16_t        i;
3626 
3627         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3628         if (buf == NULL) {
3629                 PCANDBG((CE_NOTE, "pcan cfg_scanlist: failed to alloc "
3630                     "memory(%d)\n", MAX_BUF_LEN));
3631                 return (ENOMEM);
3632         }
3633         outfp = (wldp_t *)buf;
3634         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3635 
3636         pcan_get_esslist(pcan_p, outfp->wldp_buf);
3637 
3638         outfp->wldp_length = WIFI_BUF_OFFSET +
3639             offsetof(wl_ess_list_t, wl_ess_list_ess) +
3640             pcan_p->an_scan_num * sizeof (wl_ess_conf_t);
3641         outfp->wldp_result = WL_SUCCESS;
3642         for (i = 0; i < (outfp->wldp_length); i++)
3643                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3644         kmem_free(buf, MAX_BUF_LEN);
3645         return (WL_SUCCESS);
3646 }
3647 
3648 /*ARGSUSED*/
3649 static int
3650 pcan_cfg_linkstatus(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3651 {
3652         wldp_t *outfp;
3653         char *buf;
3654         uint16_t i;
3655 
3656         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3657         if (buf == NULL) {
3658                 PCANDBG((CE_NOTE, "pcan cfg_linkstatus: failed to alloc "
3659                     "memory(%d)\n", MAX_BUF_LEN));
3660                 return (ENOMEM);
3661         }
3662         outfp = (wldp_t *)buf;
3663         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3664 
3665         pcan_get_linkstatus(pcan_p, outfp->wldp_buf);
3666 
3667         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t);
3668         outfp->wldp_result = WL_SUCCESS;
3669         for (i = 0; i < (outfp->wldp_length); i++)
3670                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3671         kmem_free(buf, MAX_BUF_LEN);
3672         return (WL_SUCCESS);
3673 }
3674 
3675 static int
3676 pcan_cfg_bsstype(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3677 {
3678         uint16_t i;
3679         wldp_t  *infp;
3680         wldp_t *outfp;
3681         char *buf;
3682         int iret;
3683 
3684         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3685         if (buf == NULL) {
3686                 PCANDBG((CE_NOTE, "pcan cfg_bsstype: failed to alloc "
3687                     "memory(%d)\n", MAX_BUF_LEN));
3688                 return (ENOMEM);
3689         }
3690         outfp = (wldp_t *)buf;
3691         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3692         infp = (wldp_t *)mp->b_rptr;
3693 
3694         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t);
3695 
3696         if (cmd == WLAN_GET_PARAM) {
3697                 pcan_get_bsstype(pcan_p, outfp->wldp_buf);
3698                 outfp->wldp_result = WL_SUCCESS;
3699         } else if (cmd == WLAN_SET_PARAM) {
3700                 (void) pcan_set_bsstype(pcan_p, infp->wldp_buf);
3701                 outfp->wldp_result = WL_SUCCESS;
3702         } else {
3703                 kmem_free(buf, MAX_BUF_LEN);
3704                 return (EINVAL);
3705         }
3706 
3707         for (i = 0; i < (outfp->wldp_length); i++)
3708                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3709         iret = (int)(outfp->wldp_result);
3710         kmem_free(buf, MAX_BUF_LEN);
3711         return (iret);
3712 }
3713 
3714 static int
3715 pcan_cfg_phy(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3716 {
3717         uint16_t        i;
3718         wldp_t          *infp;
3719         wldp_t          *outfp;
3720         char            *buf;
3721         int             iret;
3722         int             err = 0;
3723 
3724         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3725         if (buf == NULL) {
3726                 PCANDBG((CE_NOTE, "pcan cfg_phy: failed to alloc "
3727                     "memory(%d)\n", MAX_BUF_LEN));
3728                 return (ENOMEM);
3729         }
3730         outfp = (wldp_t *)buf;
3731         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3732         infp = (wldp_t *)mp->b_rptr;
3733 
3734         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t);
3735 
3736         if (cmd == WLAN_GET_PARAM) {
3737                 err = pcan_get_phy(pcan_p, outfp->wldp_buf);
3738                 if (err == EIO) {
3739                         outfp->wldp_length = WIFI_BUF_OFFSET;
3740                         outfp->wldp_result = WL_HW_ERROR;
3741                         goto done;
3742                 }
3743                 outfp->wldp_result = WL_SUCCESS;
3744         } else if (cmd == WLAN_SET_PARAM) {
3745                 err = pcan_set_phy(pcan_p, infp->wldp_buf);
3746                 if (err == ENOTSUP) {
3747                         outfp->wldp_result = WL_NOTSUPPORTED;
3748                         goto done;
3749                 }
3750                 outfp->wldp_result = WL_SUCCESS;
3751         } else {
3752                 kmem_free(buf, MAX_BUF_LEN);
3753                 return (EINVAL);
3754         }
3755 
3756 done:
3757         for (i = 0; i < (outfp->wldp_length); i++)
3758                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3759         iret = (int)(outfp->wldp_result);
3760         kmem_free(buf, MAX_BUF_LEN);
3761         return (iret);
3762 
3763 }
3764 
3765 /*ARGSUSED*/
3766 static int
3767 pcan_cfg_desiredrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3768 {
3769         uint16_t        i;
3770         wldp_t          *infp;
3771         wldp_t          *outfp;
3772         char            *buf;
3773         int             iret;
3774         int             err = 0;
3775 
3776         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3777         if (buf == NULL) {
3778                 PCANDBG((CE_NOTE, "pcan cfg_rates: failed to alloc "
3779                     "memory(%d)\n", MAX_BUF_LEN));
3780                 return (ENOMEM);
3781         }
3782         outfp = (wldp_t *)buf;
3783         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3784         infp = (wldp_t *)mp->b_rptr;
3785 
3786         if (cmd == WLAN_GET_PARAM) {
3787                 err = pcan_get_desrates(pcan_p, outfp->wldp_buf);
3788                 if (err == EIO) {
3789                         outfp->wldp_length = WIFI_BUF_OFFSET;
3790                         outfp->wldp_result = WL_HW_ERROR;
3791                         goto done;
3792                 }
3793                 outfp->wldp_length = WIFI_BUF_OFFSET +
3794                     offsetof(wl_rates_t, wl_rates_rates) + sizeof (char);
3795                 outfp->wldp_result = WL_SUCCESS;
3796         } else if (cmd == WLAN_SET_PARAM) {
3797                 (void) pcan_set_desrates(pcan_p, infp->wldp_buf);
3798                 outfp->wldp_length = WIFI_BUF_OFFSET;
3799                 outfp->wldp_result = WL_SUCCESS;
3800         } else {
3801                 kmem_free(buf, MAX_BUF_LEN);
3802                 return (EINVAL);
3803         }
3804 
3805 done:
3806         for (i = 0; i < (outfp->wldp_length); i++)
3807                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3808         iret = (int)(outfp->wldp_result);
3809         kmem_free(buf, MAX_BUF_LEN);
3810         return (iret);
3811 }
3812 
3813 /*ARGSUSED*/
3814 static int
3815 pcan_cfg_supportrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3816 {
3817         uint16_t i;
3818         int iret;
3819         wldp_t *outfp;
3820         char *buf;
3821 
3822         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3823         if (buf == NULL) {
3824                 PCANDBG((CE_NOTE, "pcan cfg_supportedrates: failed to alloc "
3825                     "memory(%d)\n", MAX_BUF_LEN));
3826                 return (ENOMEM);
3827         }
3828         outfp = (wldp_t *)buf;
3829         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3830 
3831         if (cmd == WLAN_GET_PARAM) {
3832                 pcan_get_suprates(outfp->wldp_buf);
3833                 outfp->wldp_length = WIFI_BUF_OFFSET +
3834                     offsetof(wl_rates_t, wl_rates_rates) +
3835                     4 * sizeof (char);
3836                 outfp->wldp_result = WL_SUCCESS;
3837         } else {
3838                 kmem_free(buf, MAX_BUF_LEN);
3839                 return (EINVAL);
3840         }
3841 
3842 done:
3843         for (i = 0; i < (outfp->wldp_length); i++)
3844                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3845         iret = (int)(outfp->wldp_result);
3846         kmem_free(buf, MAX_BUF_LEN);
3847         return (iret);
3848 }
3849 
3850 /*ARGSUSED*/
3851 static int
3852 pcan_cfg_powermode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3853 {
3854         uint16_t        i;
3855         wldp_t          *outfp;
3856         char            *buf;
3857         int             iret;
3858         int             err = 0;
3859 
3860         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3861         if (buf == NULL) {
3862                 PCANDBG((CE_NOTE, "pcan cfg_powermode: failed to alloc "
3863                     "memory(%d)\n", MAX_BUF_LEN));
3864                 return (ENOMEM);
3865         }
3866         outfp = (wldp_t *)buf;
3867         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3868 
3869         if (cmd == WLAN_GET_PARAM) {
3870                 err = pcan_get_powermode(pcan_p, outfp->wldp_buf);
3871                 if (err == EIO) {
3872                         outfp->wldp_length = WIFI_BUF_OFFSET;
3873                         outfp->wldp_result = WL_HW_ERROR;
3874                         goto done;
3875                 }
3876                 outfp->wldp_length = WIFI_BUF_OFFSET +
3877                     sizeof (wl_ps_mode_t);
3878                 outfp->wldp_result = WL_SUCCESS;
3879         } else if (cmd == WLAN_SET_PARAM) {
3880                 outfp->wldp_length = WIFI_BUF_OFFSET;
3881                 outfp->wldp_result = WL_LACK_FEATURE;
3882         } else {
3883                 kmem_free(buf, MAX_BUF_LEN);
3884                 return (EINVAL);
3885         }
3886 
3887 done:
3888         for (i = 0; i < (outfp->wldp_length); i++)
3889                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3890         iret = (int)(outfp->wldp_result);
3891         kmem_free(buf, MAX_BUF_LEN);
3892         return (iret);
3893 
3894 }
3895 
3896 static int
3897 pcan_cfg_authmode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3898 {
3899         uint16_t i;
3900         wldp_t *outfp;
3901         char *buf;
3902         int iret;
3903         int err = 0;
3904         struct an_ltv_genconfig *actcfg_p;
3905 
3906         actcfg_p = &pcan_p->an_actual_config;
3907 
3908         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3909         if (buf == NULL) {
3910                 PCANDBG((CE_NOTE, "pcan cfg_autymode: failed to alloc "
3911                     "memory(%d)\n", MAX_BUF_LEN));
3912                 return (ENOMEM);
3913         }
3914         outfp = (wldp_t *)buf;
3915         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3916 
3917         if (cmd == WLAN_GET_PARAM) {
3918                 pcan_get_authmode(pcan_p, outfp->wldp_buf);
3919                 outfp->wldp_result = WL_SUCCESS;
3920         } else if (cmd == WLAN_SET_PARAM) {
3921                 err = pcan_set_authmode(pcan_p, outfp->wldp_buf);
3922                 if (err == EINVAL) {
3923                         outfp->wldp_length = WIFI_BUF_OFFSET;
3924                         outfp->wldp_result = WL_LACK_FEATURE;
3925                 } else {
3926                         outfp->wldp_length = WIFI_BUF_OFFSET;
3927                         outfp->wldp_result = WL_SUCCESS;
3928                 }
3929         } else {
3930                 kmem_free(buf, MAX_BUF_LEN);
3931                 return (EINVAL);
3932         }
3933         PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.authmode=%x",
3934             actcfg_p->an_authtype));
3935         PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.home_product=%x",
3936             actcfg_p->an_rsvd6[2]));
3937 
3938         for (i = 0; i < (outfp->wldp_length); i++)
3939                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3940         iret = (int)(outfp->wldp_result);
3941         kmem_free(buf, MAX_BUF_LEN);
3942         return (iret);
3943 }
3944 
3945 static int
3946 pcan_cfg_encryption(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3947 {
3948         uint16_t i;
3949         wldp_t *outfp;
3950         char *buf;
3951         int iret;
3952 
3953         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3954         if (buf == NULL) {
3955                 PCANDBG((CE_NOTE, "pcan cfg_encryption: failed to alloc "
3956                     "memory(%d)\n", MAX_BUF_LEN));
3957                 return (ENOMEM);
3958         }
3959         outfp = (wldp_t *)buf;
3960         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3961 
3962         if (cmd == WLAN_GET_PARAM) {
3963                 pcan_get_encrypt(pcan_p, outfp->wldp_buf);
3964                 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
3965                 outfp->wldp_result = WL_SUCCESS;
3966         } else if (cmd == WLAN_SET_PARAM) {
3967                 (void) pcan_set_encrypt(pcan_p, outfp->wldp_buf);
3968                 outfp->wldp_length = WIFI_BUF_OFFSET;
3969                 outfp->wldp_result = WL_SUCCESS;
3970         } else {
3971                 kmem_free(buf, MAX_BUF_LEN);
3972                 return (EINVAL);
3973         }
3974 
3975         for (i = 0; i < (outfp->wldp_length); i++)
3976                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3977         iret = (int)(outfp->wldp_result);
3978         kmem_free(buf, MAX_BUF_LEN);
3979         return (iret);
3980 }
3981 
3982 static int
3983 pcan_cfg_wepkeyid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3984 {
3985         uint16_t i, ret;
3986         wldp_t  *infp;
3987         wldp_t *outfp;
3988         char *buf;
3989         int iret;
3990         struct an_ltv_wepkey wepkey;
3991 
3992         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3993         if (buf == NULL) {
3994                 PCANDBG((CE_NOTE, "pcan cfg_wepkeyid: failed to alloc "
3995                     "memory(%d)\n", MAX_BUF_LEN));
3996                 return (ENOMEM);
3997         }
3998         outfp = (wldp_t *)buf;
3999         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
4000         infp = (wldp_t *)mp->b_rptr;
4001 
4002         if (cmd == WLAN_GET_PARAM) {
4003                 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t);
4004                 outfp->wldp_result = WL_SUCCESS;
4005                 *(wl_wep_key_id_t *)(outfp->wldp_buf) = pcan_p->an_cur_wepkey;
4006         } else if (cmd == WLAN_SET_PARAM) {
4007                 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf));
4008                 if (ret > 3) {
4009                         kmem_free(buf, MAX_BUF_LEN);
4010                         return (EINVAL);
4011                 }
4012                 wepkey.an_index = 0xffff;
4013                 wepkey.an_macaddr[0] = ret & 0xff;
4014                 pcan_p->an_cur_wepkey = ret;
4015                 outfp->wldp_length = WIFI_BUF_OFFSET;
4016                 outfp->wldp_result = WL_SUCCESS;
4017         } else {
4018                 kmem_free(buf, MAX_BUF_LEN);
4019                 return (EINVAL);
4020         }
4021         for (i = 0; i < (outfp->wldp_length); i++)
4022                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4023         iret = (int)(outfp->wldp_result);
4024         kmem_free(buf, MAX_BUF_LEN);
4025         return (iret);
4026 }
4027 
4028 /*ARGSUSED*/
4029 static int
4030 pcan_cfg_createibss(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4031 {
4032         uint16_t i;
4033         wldp_t *outfp;
4034         char *buf;
4035         int iret;
4036 
4037         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
4038         if (buf == NULL) {
4039                 PCANDBG((CE_NOTE, "pcan cfg_createibss: failed to alloc "
4040                     "memory(%d)\n", MAX_BUF_LEN));
4041                 return (ENOMEM);
4042         }
4043         outfp = (wldp_t *)buf;
4044         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
4045 
4046         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t);
4047         outfp->wldp_result = WL_LACK_FEATURE;
4048         for (i = 0; i < (outfp->wldp_length); i++)
4049                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4050         iret = (int)(outfp->wldp_result);
4051         kmem_free(buf, MAX_BUF_LEN);
4052         return (iret);
4053 }
4054 
4055 static int
4056 pcan_cfg_rssi(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4057 {
4058         uint16_t        i;
4059         int             iret;
4060         wldp_t          *outfp;
4061         char            *buf;
4062         int             err = 0;
4063 
4064         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
4065         if (buf == NULL) {
4066                 PCANDBG((CE_NOTE, "pcan cfg_rssi: failed to alloc "
4067                     "memory(%d)\n", MAX_BUF_LEN));
4068                 return (ENOMEM);
4069         }
4070         outfp = (wldp_t *)buf;
4071         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
4072 
4073         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t);
4074 
4075         if (cmd == WLAN_GET_PARAM) {
4076                 err = pcan_get_rssi(pcan_p, outfp->wldp_buf);
4077                 if (err == EIO) {
4078                         outfp->wldp_length = WIFI_BUF_OFFSET;
4079                         outfp->wldp_result = WL_HW_ERROR;
4080                         goto done;
4081                 }
4082                 outfp->wldp_result = WL_SUCCESS;
4083         } else if (cmd == WLAN_SET_PARAM) {
4084                 outfp->wldp_result = WL_READONLY;
4085         } else {
4086                 kmem_free(buf, MAX_BUF_LEN);
4087                 return (EINVAL);
4088         }
4089 
4090 done:
4091         for (i = 0; i < (outfp->wldp_length); i++)
4092                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4093         iret = (int)(outfp->wldp_result);
4094         kmem_free(buf, MAX_BUF_LEN);
4095         return (iret);
4096 }
4097 
4098 /*ARGSUSED*/
4099 static int
4100 pcan_cfg_radio(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4101 {
4102         uint16_t i;
4103         int iret;
4104         wldp_t *outfp;
4105         char *buf;
4106 
4107         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
4108         if (buf == NULL) {
4109                 PCANDBG((CE_NOTE, "pcan cfg_radio: failed to alloc "
4110                     "memory(%d)\n", MAX_BUF_LEN));
4111                 return (ENOMEM);
4112         }
4113         outfp = (wldp_t *)buf;
4114         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
4115 
4116         if (cmd == WLAN_GET_PARAM) {
4117                 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE;
4118                 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t);
4119                 outfp->wldp_result = WL_SUCCESS;
4120         } else if (cmd == WLAN_SET_PARAM) {
4121                 outfp->wldp_length = WIFI_BUF_OFFSET;
4122                 outfp->wldp_result = WL_LACK_FEATURE;
4123         } else {
4124                 kmem_free(buf, MAX_BUF_LEN);
4125                 return (EINVAL);
4126         }
4127 
4128         for (i = 0; i < (outfp->wldp_length); i++)
4129                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4130         iret = (int)(outfp->wldp_result);
4131         kmem_free(buf, MAX_BUF_LEN);
4132         return (iret);
4133 }
4134 
4135 static int
4136 pcan_cfg_wepkey(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4137 {
4138         uint16_t i;
4139         wldp_t *outfp;
4140         char *buf;
4141         int iret;
4142         wldp_t  *infp;
4143 
4144         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
4145         if (buf == NULL) {
4146                 PCANDBG((CE_NOTE, "pcan cfg_wep: failed to alloc "
4147                     "memory(%d)\n", MAX_BUF_LEN));
4148                 return (ENOMEM);
4149         }
4150         outfp = (wldp_t *)buf;
4151         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
4152         infp = (wldp_t *)mp->b_rptr;
4153 
4154         if (cmd == WLAN_GET_PARAM) {
4155                 outfp->wldp_length = WIFI_BUF_OFFSET +
4156                     sizeof (wl_wep_key_tab_t);
4157                 outfp->wldp_result = WL_WRITEONLY;
4158         } else if (cmd == WLAN_SET_PARAM) {
4159                 (void) pcan_set_wepkey(pcan_p, infp->wldp_buf);
4160                 outfp->wldp_length = WIFI_BUF_OFFSET;
4161                 outfp->wldp_result = WL_SUCCESS;
4162         } else {
4163                 kmem_free(buf, MAX_BUF_LEN);
4164                 return (EINVAL);
4165         }
4166 
4167         for (i = 0; i < (outfp->wldp_length); i++)
4168                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4169         iret = (int)(outfp->wldp_result);
4170         kmem_free(buf, MAX_BUF_LEN);
4171         return (iret);
4172 }
4173 
4174 static void
4175 pcan_connect_timeout(void *arg)
4176 {
4177         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
4178         uint16_t ret;
4179 
4180         mutex_enter(&pcan_p->pcan_glock);
4181         if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
4182                 goto done;
4183         pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4184         if (ret = pcan_config_mac(pcan_p))
4185                 goto done;
4186         ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0);
4187 done:
4188         if (ret)
4189                 cmn_err(CE_WARN, "pcan: connect failed due to hardware error");
4190         mutex_exit(&pcan_p->pcan_glock);
4191         pcan_p->pcan_connect_timeout_id = 0;
4192 }
4193 
4194 static int
4195 pcan_getset(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4196 {
4197         int ret = WL_SUCCESS;
4198         int connect = 0;
4199 
4200         mutex_enter(&pcan_p->pcan_glock);
4201         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4202                 mutex_exit(&pcan_p->pcan_glock);
4203                 return (PCAN_FAIL);
4204         }
4205 
4206         switch (((wldp_t *)mp->b_rptr)->wldp_id) {
4207         case WL_ESSID:
4208                 ret = pcan_cfg_essid(mp, pcan_p, cmd);
4209                 connect = 1;
4210                 PCANDBG((CE_NOTE, "cfg_essid\n"));
4211                 break;
4212         case WL_BSSID:
4213                 ret = pcan_cfg_bssid(mp, pcan_p, cmd);
4214                 connect = 1;
4215                 PCANDBG((CE_NOTE, "cfg_bssid\n"));
4216                 break;
4217         case WL_ESS_LIST:
4218                 ret = pcan_cfg_scan(mp, pcan_p, cmd);
4219                 PCANDBG((CE_NOTE, "cfg_scan\n"));
4220                 break;
4221         case WL_LINKSTATUS:
4222                 ret = pcan_cfg_linkstatus(mp, pcan_p, cmd);
4223                 PCANDBG((CE_NOTE, "cfg_linkstatus\n"));
4224                 break;
4225         case WL_BSS_TYPE:
4226                 ret = pcan_cfg_bsstype(mp, pcan_p, cmd);
4227                 connect = 1;
4228                 PCANDBG((CE_NOTE, "cfg_bsstype\n"));
4229                 break;
4230         case WL_PHY_CONFIG:
4231                 ret = pcan_cfg_phy(mp, pcan_p, cmd);
4232                 connect = 1;
4233                 PCANDBG((CE_NOTE, "cfg_phy\n"));
4234                 break;
4235         case WL_DESIRED_RATES:
4236                 ret = pcan_cfg_desiredrates(mp, pcan_p, cmd);
4237                 connect = 1;
4238                 PCANDBG((CE_NOTE, "cfg_disred-rates\n"));
4239                 break;
4240         case WL_SUPPORTED_RATES:
4241                 ret = pcan_cfg_supportrates(mp, pcan_p, cmd);
4242                 PCANDBG((CE_NOTE, "cfg_supported-rates\n"));
4243                 break;
4244         case WL_POWER_MODE:
4245                 ret = pcan_cfg_powermode(mp, pcan_p, cmd);
4246                 PCANDBG((CE_NOTE, "cfg_powermode\n"));
4247                 break;
4248         case WL_AUTH_MODE:
4249                 ret = pcan_cfg_authmode(mp, pcan_p, cmd);
4250                 connect = 1;
4251                 PCANDBG((CE_NOTE, "cfg_authmode\n"));
4252                 break;
4253         case WL_ENCRYPTION:
4254                 ret = pcan_cfg_encryption(mp, pcan_p, cmd);
4255                 connect = 1;
4256                 PCANDBG((CE_NOTE, "cfg_encryption\n"));
4257                 break;
4258         case WL_WEP_KEY_ID:
4259                 ret = pcan_cfg_wepkeyid(mp, pcan_p, cmd);
4260                 connect = 1;
4261                 PCANDBG((CE_NOTE, "cfg_wepkeyid\n"));
4262                 break;
4263         case WL_CREATE_IBSS:
4264                 ret = pcan_cfg_createibss(mp, pcan_p, cmd);
4265                 connect = 1;
4266                 PCANDBG((CE_NOTE, "cfg_create-ibss\n"));
4267                 break;
4268         case WL_RSSI:
4269                 ret = pcan_cfg_rssi(mp, pcan_p, cmd);
4270                 PCANDBG((CE_NOTE, "cfg_rssi\n"));
4271                 break;
4272         case WL_RADIO:
4273                 ret = pcan_cfg_radio(mp, pcan_p, cmd);
4274                 PCANDBG((CE_NOTE, "cfg_radio\n"));
4275                 break;
4276         case WL_WEP_KEY_TAB:
4277                 ret = pcan_cfg_wepkey(mp, pcan_p, cmd);
4278                 connect = 1;
4279                 PCANDBG((CE_NOTE, "cfg_wepkey\n"));
4280                 break;
4281         case WL_SCAN:
4282                 mutex_exit(&pcan_p->pcan_glock);
4283                 if (pcan_p->pcan_connect_timeout_id != 0) {
4284                         (void) untimeout(pcan_p->pcan_connect_timeout_id);
4285                         pcan_p->pcan_connect_timeout_id = 0;
4286                 }
4287                 mutex_enter(&pcan_p->pcan_glock);
4288                 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4289                         mutex_exit(&pcan_p->pcan_glock);
4290                         return (PCAN_FAIL);
4291                 }
4292                 ret = pcan_cmd_scan(pcan_p);
4293                 /*
4294                  * a trick here.
4295                  * since the scan doesn't return too many items due to hardware
4296                  * reason, so the current scan result is an accumulation of
4297                  * several scans. For the first time or after many of the items
4298                  * aged, we scan again if too few items now in the scan table.
4299                  */
4300                 if (pcan_p->an_scan_num < AN_SCAN_AGAIN_THRESHOLD)
4301                         ret = pcan_cmd_scan(pcan_p);
4302                 break;
4303         case WL_LOAD_DEFAULTS:
4304                 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
4305                         ret = (int)WL_HW_ERROR;
4306                         break;
4307                 }
4308                 if (ret = pcan_loaddef(pcan_p)) {
4309                         ret = (int)WL_HW_ERROR;
4310                         break;
4311                 }
4312                 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
4313                         ret = (int)WL_HW_ERROR;
4314                         break;
4315                 }
4316                 PCANDBG((CE_NOTE, "loaddef\n"));
4317                 break;
4318         case WL_DISASSOCIATE:
4319                 mutex_exit(&pcan_p->pcan_glock);
4320                 if (pcan_p->pcan_connect_timeout_id != 0) {
4321                         (void) untimeout(pcan_p->pcan_connect_timeout_id);
4322                         pcan_p->pcan_connect_timeout_id = 0;
4323                 }
4324                 mutex_enter(&pcan_p->pcan_glock);
4325                 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4326                         mutex_exit(&pcan_p->pcan_glock);
4327                         return (PCAN_FAIL);
4328                 }
4329                 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4330                 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
4331                         ret = (int)WL_HW_ERROR;
4332                         break;
4333                 }
4334                 if (ret = pcan_loaddef(pcan_p)) {
4335                         ret = (int)WL_HW_ERROR;
4336                         break;
4337                 }
4338                 PCANDBG((CE_NOTE, "disassociate\n"));
4339                 break;
4340         case WL_REASSOCIATE:
4341         case WL_ASSOCIAT:
4342                 mutex_exit(&pcan_p->pcan_glock);
4343                 if (pcan_p->pcan_connect_timeout_id != 0) {
4344                         (void) untimeout(pcan_p->pcan_connect_timeout_id);
4345                         pcan_p->pcan_connect_timeout_id = 0;
4346                 }
4347                 mutex_enter(&pcan_p->pcan_glock);
4348                 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4349                         mutex_exit(&pcan_p->pcan_glock);
4350                         return (PCAN_FAIL);
4351                 }
4352                 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
4353                         ret = (int)WL_HW_ERROR;
4354                         break;
4355                 }
4356                 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4357                 if (ret = pcan_config_mac(pcan_p)) {
4358                         ret = (int)WL_HW_ERROR;
4359                         break;
4360                 }
4361                 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
4362                         ret = (int)WL_HW_ERROR;
4363                         break;
4364                 }
4365                 PCANDBG((CE_NOTE, "associate"));
4366                 break;
4367 
4368         default:
4369                 break;
4370         }
4371         mutex_exit(&pcan_p->pcan_glock);
4372         if ((cmd == WLAN_SET_PARAM) && (ret == WL_SUCCESS) && (connect)) {
4373                 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4374                 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
4375                 if (pcan_p->pcan_connect_timeout_id != 0) {
4376                         (void) untimeout(pcan_p->pcan_connect_timeout_id);
4377                         pcan_p->pcan_connect_timeout_id = 0;
4378                 }
4379                 pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout,
4380                     pcan_p, drv_usectohz(1000000));
4381         }
4382         return (ret);
4383 }
4384 
4385 static void
4386 pcan_wlan_ioctl(pcan_maci_t *pcan_p, queue_t *wq, mblk_t *mp, uint32_t cmd)
4387 {
4388 
4389         struct  iocblk  *iocp = (struct iocblk *)mp->b_rptr;
4390         uint32_t len, ret;
4391         mblk_t  *mp1;
4392 
4393         /* sanity check */
4394         if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) {
4395                 miocnak(wq, mp, 0, EINVAL);
4396                 return;
4397         }
4398 
4399         /* assuming single data block */
4400         if (mp1->b_cont) {
4401                 freemsg(mp1->b_cont);
4402                 mp1->b_cont = NULL;
4403         }
4404 
4405         /* we will overwrite everything */
4406         mp1->b_wptr = mp1->b_rptr;
4407 
4408         ret = pcan_getset(mp1, pcan_p, cmd);
4409         len = msgdsize(mp1);
4410         miocack(wq, mp, len, ret);
4411 }
4412 
4413 static void
4414 pcan_ioctl(void *arg, queue_t *wq, mblk_t *mp)
4415 {
4416         struct iocblk *iocp;
4417         uint32_t cmd, ret;
4418         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
4419         boolean_t need_privilege = B_TRUE;
4420 
4421         iocp = (struct iocblk *)mp->b_rptr;
4422         iocp->ioc_error = 0;
4423         cmd = iocp->ioc_cmd;
4424         switch (cmd) {
4425         default:
4426                 miocnak(wq, mp, 0, EINVAL);
4427                 return;
4428         case WLAN_GET_PARAM:
4429                 need_privilege = B_FALSE;
4430                 break;
4431         case WLAN_SET_PARAM:
4432         case WLAN_COMMAND:
4433                 break;
4434         }
4435 
4436         if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0)
4437                 miocnak(wq, mp, 0, ret);
4438         else
4439                 pcan_wlan_ioctl(pcan_p, wq, mp, cmd);
4440 }
4441 /*
4442  * brussels
4443  */
4444 /* ARGSUSED */
4445 static int
4446 pcan_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4447     uint_t wldp_length, const void *wldp_buf)
4448 {
4449         int             err = 0;
4450         pcan_maci_t     *pcan_p = (pcan_maci_t *)arg;
4451 
4452         mutex_enter(&pcan_p->pcan_glock);
4453         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4454                 mutex_exit(&pcan_p->pcan_glock);
4455                 err = EINVAL;
4456                 return (err);
4457         }
4458 
4459         switch (wldp_pr_num) {
4460         /* mac_prop_id */
4461         case MAC_PROP_WL_ESSID:
4462                 err = pcan_set_essid(pcan_p, wldp_buf);
4463                 break;
4464         case MAC_PROP_WL_BSSID:
4465                 err = pcan_set_bssid(pcan_p, wldp_buf);
4466                 break;
4467         case MAC_PROP_WL_PHY_CONFIG:
4468                 err = pcan_set_phy(pcan_p, wldp_buf);
4469                 break;
4470         case MAC_PROP_WL_KEY_TAB:
4471                 err = pcan_set_wepkey(pcan_p, wldp_buf);
4472                 break;
4473         case MAC_PROP_WL_AUTH_MODE:
4474                 err = pcan_set_authmode(pcan_p, wldp_buf);
4475                 break;
4476         case MAC_PROP_WL_ENCRYPTION:
4477                 err = pcan_set_encrypt(pcan_p, wldp_buf);
4478                 break;
4479         case MAC_PROP_WL_BSSTYPE:
4480                 err = pcan_set_bsstype(pcan_p, wldp_buf);
4481                 break;
4482         case MAC_PROP_WL_DESIRED_RATES:
4483                 err = pcan_set_desrates(pcan_p, wldp_buf);
4484                 break;
4485         case MAC_PROP_WL_POWER_MODE:
4486         case MAC_PROP_WL_CREATE_IBSS:
4487         case MAC_PROP_WL_RADIO:
4488         case MAC_PROP_WL_WPA:
4489         case MAC_PROP_WL_KEY:
4490         case MAC_PROP_WL_DELKEY:
4491         case MAC_PROP_WL_SETOPTIE:
4492         case MAC_PROP_WL_MLME:
4493         case MAC_PROP_WL_LINKSTATUS:
4494         case MAC_PROP_WL_ESS_LIST:
4495         case MAC_PROP_WL_SUPPORTED_RATES:
4496         case MAC_PROP_WL_RSSI:
4497         case MAC_PROP_WL_CAPABILITY:
4498         case MAC_PROP_WL_SCANRESULTS:
4499                 cmn_err(CE_WARN, "pcan_setprop:"
4500                     "opmode not support\n");
4501                 err = ENOTSUP;
4502                 break;
4503         default:
4504                 cmn_err(CE_WARN, "pcan_setprop:"
4505                     "opmode err\n");
4506                 err = EINVAL;
4507                 break;
4508         }
4509 
4510         mutex_exit(&pcan_p->pcan_glock);
4511 
4512         if (err == ENETRESET) {
4513                 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4514                 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
4515                 if (pcan_p->pcan_connect_timeout_id != 0) {
4516                         (void) untimeout(pcan_p->pcan_connect_timeout_id);
4517                         pcan_p->pcan_connect_timeout_id = 0;
4518                 }
4519                 pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout,
4520                     pcan_p, drv_usectohz(1000000));
4521 
4522                 err = 0;
4523         }
4524 
4525         return (err);
4526 } /* ARGSUSED */
4527 
4528 /* ARGSUSED */
4529 static int
4530 pcan_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4531     uint_t wldp_length, void *wldp_buf)
4532 {
4533         int err = 0;
4534         pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
4535 
4536         mutex_enter(&pcan_p->pcan_glock);
4537         if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4538                 mutex_exit(&pcan_p->pcan_glock);
4539                 err = EINVAL;
4540                 return (err);
4541         }
4542 
4543         switch (wldp_pr_num) {
4544         /* mac_prop_id */
4545         case MAC_PROP_WL_ESSID:
4546                 err = pcan_get_essid(pcan_p, wldp_buf);
4547                 break;
4548         case MAC_PROP_WL_BSSID:
4549                 err = pcan_get_bssid(pcan_p, wldp_buf);
4550                 break;
4551         case MAC_PROP_WL_PHY_CONFIG:
4552                 err = pcan_get_phy(pcan_p, wldp_buf);
4553                 break;
4554         case MAC_PROP_WL_AUTH_MODE:
4555                 pcan_get_authmode(pcan_p, wldp_buf);
4556                 break;
4557         case MAC_PROP_WL_ENCRYPTION:
4558                 pcan_get_encrypt(pcan_p, wldp_buf);
4559                 break;
4560         case MAC_PROP_WL_BSSTYPE:
4561                 pcan_get_bsstype(pcan_p, wldp_buf);
4562                 break;
4563         case MAC_PROP_WL_LINKSTATUS:
4564                 pcan_get_linkstatus(pcan_p, wldp_buf);
4565                 break;
4566         case MAC_PROP_WL_ESS_LIST:
4567                 pcan_get_esslist(pcan_p, wldp_buf);
4568                 break;
4569         case MAC_PROP_WL_SUPPORTED_RATES:
4570                 pcan_get_suprates(wldp_buf);
4571                 break;
4572         case MAC_PROP_WL_RSSI:
4573                 err = pcan_get_rssi(pcan_p, wldp_buf);
4574                 break;
4575         case MAC_PROP_WL_RADIO:
4576                 pcan_get_radio(wldp_buf);
4577                 break;
4578         case MAC_PROP_WL_POWER_MODE:
4579                 err = pcan_get_powermode(pcan_p, wldp_buf);
4580                 break;
4581         case MAC_PROP_WL_DESIRED_RATES:
4582                 err = pcan_get_desrates(pcan_p, wldp_buf);
4583                 break;
4584         case MAC_PROP_WL_CREATE_IBSS:
4585         case MAC_PROP_WL_CAPABILITY:
4586         case MAC_PROP_WL_WPA:
4587         case MAC_PROP_WL_SCANRESULTS:
4588         case MAC_PROP_WL_KEY_TAB:
4589         case MAC_PROP_WL_KEY:
4590         case MAC_PROP_WL_DELKEY:
4591         case MAC_PROP_WL_SETOPTIE:
4592         case MAC_PROP_WL_MLME:
4593                 cmn_err(CE_WARN, "pcan_getprop:"
4594                     "opmode not support %x\n", wldp_pr_num);
4595                 err = ENOTSUP;
4596                 break;
4597         default:
4598                 cmn_err(CE_WARN, "pcan_getprop:"
4599                     "opmode err\n");
4600                 err = EINVAL;
4601                 break;
4602         }
4603 
4604         mutex_exit(&pcan_p->pcan_glock);
4605 
4606         return (err);
4607 }
4608 
4609 static void
4610 pcan_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4611     mac_prop_info_handle_t mph)
4612 {
4613         _NOTE(ARGUNUSED(arg, pr_name));
4614 
4615         switch (wldp_pr_num) {
4616         case MAC_PROP_WL_BSSTYPE:
4617         case MAC_PROP_WL_ESS_LIST:
4618         case MAC_PROP_WL_SUPPORTED_RATES:
4619         case MAC_PROP_WL_RSSI:
4620                 mac_prop_info_set_perm(mph, MAC_PROP_PERM_READ);
4621                 break;
4622         }
4623 }
4624 
4625 
4626 /*
4627  * quiesce(9E) entry point.
4628  *
4629  * This function is called when the system is single-threaded at high
4630  * PIL with preemption disabled. Therefore, this function must not be
4631  * blocked.
4632  *
4633  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4634  * DDI_FAILURE indicates an error condition and should almost never happen.
4635  */
4636 #ifndef __sparc
4637 static int
4638 pcan_quiesce(dev_info_t *dip)
4639 {
4640         pcan_maci_t *pcan_p;
4641 
4642         pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip));
4643         if (pcan_p == NULL)
4644                 return (DDI_FAILURE);
4645 
4646         if (pcan_p->pcan_flag & PCAN_CARD_READY)
4647                 pcan_stop_locked(pcan_p);
4648 
4649         return (DDI_SUCCESS);
4650 }
4651 #endif