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 "pcwl.h"
  57 #include <sys/mac_wifi.h>
  58 #include <inet/wifi_ioctl.h>
  59 
  60 #ifdef DEBUG
  61 #define PCWL_DBG_BASIC          0x1
  62 #define PCWL_DBG_INFO           0x2
  63 #define PCWL_DBG_SEND           0x4
  64 #define PCWL_DBG_RCV            0x8
  65 #define PCWL_DBG_LINKINFO       0x10
  66 uint32_t pcwl_debug = 0;
  67 #define PCWLDBG(x) \
  68         if (pcwl_debug & PCWL_DBG_BASIC) cmn_err x
  69 #else
  70 #define PCWLDBG(x)
  71 #endif
  72 
  73 /* for pci card */
  74 static ddi_device_acc_attr_t accattr = {
  75                 DDI_DEVICE_ATTR_V0,
  76                 DDI_NEVERSWAP_ACC,
  77                 DDI_STRICTORDER_ACC,
  78                 DDI_DEFAULT_ACC
  79 };
  80 
  81 void *pcwl_soft_state_p = NULL;
  82 static int pcwl_device_type;
  83 
  84 static int      pcwl_m_setprop(void *arg, const char *pr_name,
  85     mac_prop_id_t wldp_pr_num, uint_t wldp_length,
  86     const void *wldp_buf);
  87 static int      pcwl_m_getprop(void *arg, const char *pr_name,
  88     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
  89 static void     pcwl_m_propinfo(void *arg, const char *pr_name,
  90     mac_prop_id_t wlpd_pr_num, mac_prop_info_handle_t mph);
  91 static void
  92 pcwl_delay(pcwl_maci_t *, clock_t);
  93 
  94 mac_callbacks_t pcwl_m_callbacks = {
  95         MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
  96         pcwl_gstat,
  97         pcwl_start,
  98         pcwl_stop,
  99         pcwl_prom,
 100         pcwl_sdmulti,
 101         pcwl_saddr,
 102         pcwl_tx,
 103         NULL,
 104         pcwl_ioctl,
 105         NULL,
 106         NULL,
 107         NULL,
 108         pcwl_m_setprop,
 109         pcwl_m_getprop,
 110         pcwl_m_propinfo
 111 };
 112 
 113 static char *pcwl_name_str = "pcwl";
 114 
 115 #ifdef  __sparc
 116 #define pcwl_quiesce    ddi_quiesce_not_supported
 117 #else
 118 static int pcwl_quiesce(dev_info_t *);
 119 #endif
 120 
 121 DDI_DEFINE_STREAM_OPS(pcwl_dev_ops, nulldev, pcwl_probe, pcwl_attach,
 122     pcwl_detach, nodev, NULL, D_MP, NULL, pcwl_quiesce);
 123 
 124 extern struct mod_ops mod_driverops;
 125 static struct modldrv modldrv = {
 126         &mod_driverops,
 127         "Lucent/PRISM-II 802.11b driver",
 128         &pcwl_dev_ops
 129 };
 130 
 131 static struct modlinkage modlinkage = {
 132         MODREV_1, (void *)&modldrv, NULL
 133         };
 134 
 135 int
 136 _init(void)
 137 {
 138         int stat;
 139 
 140         /* Allocate soft state */
 141         if ((stat = ddi_soft_state_init(&pcwl_soft_state_p,
 142             sizeof (pcwl_maci_t), N_PCWL)) != DDI_SUCCESS)
 143                 return (stat);
 144 
 145         mac_init_ops(&pcwl_dev_ops, "pcwl");
 146         wl_frame_default.wl_dat[0] = htons(WL_SNAP_WORD0);
 147         wl_frame_default.wl_dat[1] = htons(WL_SNAP_WORD1);
 148         stat = mod_install(&modlinkage);
 149         if (stat != DDI_SUCCESS) {
 150                 mac_fini_ops(&pcwl_dev_ops);
 151                 ddi_soft_state_fini(&pcwl_soft_state_p);
 152         }
 153         return (stat);
 154 }
 155 
 156 int
 157 _fini(void)
 158 {
 159         int stat;
 160 
 161         if ((stat = mod_remove(&modlinkage)) != DDI_SUCCESS)
 162                 return (stat);
 163         mac_fini_ops(&pcwl_dev_ops);
 164         ddi_soft_state_fini(&pcwl_soft_state_p);
 165 
 166         return (stat);
 167 }
 168 
 169 int
 170 _info(struct modinfo *modinfop)
 171 {
 172         return (mod_info(&modlinkage, modinfop));
 173 }
 174 
 175 static int
 176 pcwl_probe(dev_info_t *dip)
 177 {
 178         int len, ret;
 179         char *buf;
 180         dev_info_t *pdip = ddi_get_parent(dip);
 181 
 182         ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type",
 183             (caddr_t)&buf, &len);
 184         if (ret != DDI_SUCCESS)
 185                 return (DDI_PROBE_FAILURE);
 186 
 187         PCWLDBG((CE_NOTE, "pcwl probe: device_type %s\n", buf));
 188         if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) {
 189                 pcwl_device_type = PCWL_DEVICE_PCCARD;
 190                 ret = DDI_PROBE_SUCCESS;
 191         } else if (strcmp(buf, "pci") == 0) {
 192                 pcwl_device_type = PCWL_DEVICE_PCI;
 193                 ret = DDI_PROBE_SUCCESS;
 194         } else {
 195                 ret = DDI_PROBE_FAILURE;
 196         }
 197         kmem_free(buf, len);
 198         return (ret);
 199 }
 200 
 201 static int
 202 pcwl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 203 {
 204         int ret, i;
 205         int instance;
 206         uint16_t stat;
 207         uint32_t err;
 208         pcwl_maci_t *pcwl_p;
 209         wifi_data_t     wd = { 0 };
 210         mac_register_t  *macp;
 211         modify_config_t cfgmod;
 212         char strbuf[256];
 213 
 214         PCWLDBG((CE_NOTE, "pcwl attach: dip=0x%p cmd=%x\n", (void *)dip, cmd));
 215         if (cmd != DDI_ATTACH)
 216                 goto attach_fail1;
 217         /*
 218          * Allocate soft state associated with this instance.
 219          */
 220         if (ddi_soft_state_zalloc(pcwl_soft_state_p,
 221             ddi_get_instance(dip)) != DDI_SUCCESS) {
 222                 cmn_err(CE_CONT, "pcwl attach: alloc softstate failed\n");
 223                 goto attach_fail1;
 224         }
 225         pcwl_p = (pcwl_maci_t *)ddi_get_soft_state(pcwl_soft_state_p,
 226             ddi_get_instance(dip));
 227         pcwl_p->pcwl_device_type = pcwl_device_type;
 228         if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
 229                 if (ddi_regs_map_setup(dip, 0,
 230                     (caddr_t *)&pcwl_p->pcwl_cfg_base, 0, 0,
 231                     &accattr, &pcwl_p->pcwl_cfg_handle) != DDI_SUCCESS) {
 232                         cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup"
 233                             " failed\n");
 234                         goto attach_fail2;
 235                 }
 236 
 237                 stat = ddi_get16(pcwl_p->pcwl_cfg_handle,
 238                     (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM));
 239                 stat |= (PCI_COMM_IO | PCI_COMM_MAE);
 240                 ddi_put16(pcwl_p->pcwl_cfg_handle,
 241                     (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM), stat);
 242                 stat = ddi_get16(pcwl_p->pcwl_cfg_handle,
 243                     (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM));
 244                 if ((stat & (PCI_COMM_IO | PCI_COMM_MAE)) !=
 245                     (PCI_COMM_IO | PCI_COMM_MAE)) {
 246                         cmn_err(CE_WARN, "pcwl(pci) attach: pci command"
 247                             " reg enable failed\n");
 248                         goto attach_fail2a;
 249                 }
 250 
 251 
 252                 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcwl_p->pcwl_bar,
 253                     0, 0, &accattr, (ddi_acc_handle_t *)&pcwl_p->pcwl_handle)
 254                     != DDI_SUCCESS) {
 255                         cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup"
 256                             " failed\n");
 257                         goto attach_fail2a;
 258                 }
 259                 PCWLDBG((CE_NOTE, "pcwl(pci): regs_map_setup,bar=%p\n",
 260                     (void *)pcwl_p->pcwl_bar));
 261 
 262                 /*
 263                  * tricky! copy from freebsd code.
 264                  */
 265                 PCWL_WRITE(pcwl_p, 0x26, 0x80);
 266                 drv_usecwait(500000);
 267                 PCWL_WRITE(pcwl_p, 0x26, 0x0);
 268                 drv_usecwait(500000);
 269 
 270                 for (i = 0; i < WL_TIMEOUT; i++) {
 271                         PCWL_READ(pcwl_p, 0x0, stat);
 272                         if (stat & WL_CMD_BUSY)
 273                                 drv_usecwait(10);
 274                         else
 275                                 break;
 276                 }
 277                 if (i == WL_TIMEOUT) {
 278                         cmn_err(CE_WARN, "pcwl(pci) attach: hardware init"
 279                             " failed\n");
 280                         goto attach_fail3;
 281                 }
 282 
 283                 /*
 284                  * magic number verification.
 285                  * tricky! copy from freebsd code.
 286                  */
 287                 PCWL_WRITE(pcwl_p, 0x28, 0x4a2d);
 288                 PCWL_READ(pcwl_p, 0x28, stat);
 289                 PCWLDBG((CE_NOTE, "pcwl(pci):magic number = %x\n", stat));
 290                 if (stat != 0x4a2d) {
 291                         cmn_err(CE_WARN, "pcwl(pci) attach: magic verify"
 292                             " failed\n");
 293                         goto attach_fail3;
 294                 }
 295         }
 296         pcwl_p->pcwl_dip     = dip;
 297         pcwl_p->pcwl_flag    = 0;
 298         pcwl_p->pcwl_socket  = ddi_getprop(DDI_DEV_T_NONE, dip,
 299             DDI_PROP_DONTPASS, "socket", -1);
 300         pcwl_p->pcwl_reschedule_need = B_FALSE;
 301 
 302         if (ddi_get_iblock_cookie(dip,
 303             0, &pcwl_p->pcwl_ib_cookie) != DDI_SUCCESS) {
 304                 cmn_err(CE_WARN, "pcwl attach: get_iblk_cookie failed\n");
 305                 goto attach_fail3;
 306         }
 307 
 308         mutex_init(&pcwl_p->pcwl_glock, NULL, MUTEX_DRIVER,
 309             pcwl_p->pcwl_ib_cookie);
 310         mutex_init(&pcwl_p->pcwl_scanlist_lock, NULL, MUTEX_DRIVER,
 311             pcwl_p->pcwl_ib_cookie);
 312         mutex_init(&pcwl_p->pcwl_txring.wl_tx_lock, NULL, MUTEX_DRIVER,
 313             pcwl_p->pcwl_ib_cookie);
 314 
 315         if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
 316                 if (ret = ddi_add_intr(dip, 0, NULL, NULL,
 317                     pcwl_intr, (caddr_t)pcwl_p)) {
 318                         cmn_err(CE_NOTE, "pcwl(pci) attach: add intr failed\n");
 319                         goto attach_fail3a;
 320                 }
 321         } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
 322                 if (ret = pcwl_register_cs(dip, pcwl_p)) {
 323                         cmn_err(CE_WARN, "pcwl attach(pccard): "
 324                             "register_cs err %x\n", ret);
 325                         goto attach_fail3a;
 326                 }
 327         } else {
 328                 cmn_err(CE_WARN, "pcwl attach: unsupported device type\n");
 329                 goto attach_fail3a;
 330         }
 331         mutex_enter(&pcwl_p->pcwl_glock);
 332         if (ret = pcwl_reset_backend(pcwl_p)) {
 333                 cmn_err(CE_WARN, "pcwl attach: reset_backend failed %x\n", ret);
 334                 mutex_exit(&pcwl_p->pcwl_glock);
 335                 goto attach_fail4;
 336         }
 337         if (ret = pcwl_get_cap(pcwl_p)) { /* sets macaddr for mac_register */
 338                 cmn_err(CE_WARN, "pcwl attach: get_cap failed %x\n", ret);
 339                 mutex_exit(&pcwl_p->pcwl_glock);
 340                 goto attach_fail4;
 341         }
 342         mutex_exit(&pcwl_p->pcwl_glock);
 343         /*
 344          * Provide initial settings for the WiFi plugin; whenever this
 345          * information changes, we need to call mac_pdata_update()
 346          */
 347         wd.wd_secalloc = WIFI_SEC_NONE;
 348         wd.wd_opmode = IEEE80211_M_STA;
 349 
 350         macp = mac_alloc(MAC_VERSION);
 351         if (macp == NULL) {
 352                 PCWLDBG((CE_NOTE, "pcwl attach: "
 353                     "MAC version mismatch\n"));
 354                 goto attach_fail4;
 355         }
 356 
 357         macp->m_type_ident   = MAC_PLUGIN_IDENT_WIFI;
 358         macp->m_driver               = pcwl_p;
 359         macp->m_dip          = dip;
 360         macp->m_src_addr     = pcwl_p->pcwl_mac_addr;
 361         macp->m_callbacks    = &pcwl_m_callbacks;
 362         macp->m_min_sdu              = 0;
 363         macp->m_max_sdu              = IEEE80211_MTU;
 364         macp->m_pdata                = &wd;
 365         macp->m_pdata_size   = sizeof (wd);
 366 
 367         err = mac_register(macp, &pcwl_p->pcwl_mh);
 368         mac_free(macp);
 369         if (err != 0) {
 370                 PCWLDBG((CE_NOTE, "pcwl attach: "
 371                     "mac_register err\n"));
 372                 goto attach_fail4;
 373         }
 374 
 375         mutex_enter(&pcwl_p->pcwl_glock);
 376         if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
 377                 /*
 378                  * turn on CS interrupt
 379                  */
 380                 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
 381                     CONF_IRQ_CHANGE_VALID;
 382                 cfgmod.Vpp1 = 0;
 383                 cfgmod.Vpp2 = 0;
 384                 (void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod);
 385 
 386         }
 387         if (ret = pcwl_init_nicmem(pcwl_p)) {
 388                 cmn_err(CE_WARN, "pcwl(pccard) attach: pcwl_init_nicmem"
 389                     " failed %x\n", ret);
 390                 mutex_exit(&pcwl_p->pcwl_glock);
 391                 goto attach_fail5;
 392         }
 393         pcwl_chip_type(pcwl_p);
 394         if (ret = pcwl_loaddef_rf(pcwl_p)) {
 395                 cmn_err(CE_WARN, "pcwl attach: config_rf failed%x\n", ret);
 396                 mutex_exit(&pcwl_p->pcwl_glock);
 397                 goto attach_fail5;
 398         }
 399         (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
 400         pcwl_stop_locked(pcwl_p);       /* leaves interface down */
 401         list_create(&pcwl_p->pcwl_scan_list, sizeof (wl_scan_list_t),
 402             offsetof(wl_scan_list_t, wl_scan_node));
 403         pcwl_p->pcwl_scan_num = 0;
 404         mutex_exit(&pcwl_p->pcwl_glock);
 405         pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout,
 406             pcwl_p, drv_usectohz(1000000));
 407         instance = ddi_get_instance(dip);
 408         (void) snprintf(strbuf, sizeof (strbuf), "pcwl%d", instance);
 409         if (ddi_create_minor_node(dip, strbuf, S_IFCHR,
 410             instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) {
 411                 goto attach_fail6;
 412         }
 413         pcwl_p->pcwl_flag |= PCWL_ATTACHED;
 414         if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
 415                 pcwl_p->pcwl_flag |= PCWL_CARD_READY;
 416         }
 417         return (DDI_SUCCESS);
 418 attach_fail6:
 419         if (pcwl_p->pcwl_scanlist_timeout_id != 0) {
 420                 (void) untimeout(pcwl_p->pcwl_scanlist_timeout_id);
 421                 pcwl_p->pcwl_scanlist_timeout_id = 0;
 422         }
 423         list_destroy(&pcwl_p->pcwl_scan_list);
 424 attach_fail5:
 425         (void) mac_unregister(pcwl_p->pcwl_mh);
 426 attach_fail4:
 427         if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
 428                 ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie);
 429         } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
 430                 pcwl_unregister_cs(pcwl_p);
 431         }
 432 attach_fail3a:
 433         pcwl_destroy_locks(pcwl_p);
 434 attach_fail3:
 435         if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
 436                 ddi_regs_map_free(&pcwl_p->pcwl_handle);
 437 attach_fail2a:
 438         if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
 439                 ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
 440 attach_fail2:
 441         ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
 442 attach_fail1:
 443         return (DDI_FAILURE);
 444 }
 445 
 446 static int
 447 pcwl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 448 {
 449         pcwl_maci_t *pcwl_p;
 450         wl_scan_list_t *scan_item0;
 451         int ret;
 452         pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip));
 453 
 454         PCWLDBG((CE_NOTE, "pcwl detach: dip=0x%p cmd=%x\n", (void *)dip, cmd));
 455         if (cmd != DDI_DETACH)
 456                 return (DDI_FAILURE);
 457         if (!(pcwl_p->pcwl_flag & PCWL_ATTACHED))
 458                 return (DDI_FAILURE);
 459 
 460         ret = mac_disable(pcwl_p->pcwl_mh);
 461         if (ret != 0)
 462                 return (DDI_FAILURE);
 463 
 464         if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
 465                 mutex_enter(&pcwl_p->pcwl_glock);
 466                 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
 467                 PCWL_DISABLE_INTR(pcwl_p);
 468                 mutex_exit(&pcwl_p->pcwl_glock);
 469         }
 470         if (pcwl_p->pcwl_scanlist_timeout_id != 0) {
 471                 (void) untimeout(pcwl_p->pcwl_scanlist_timeout_id);
 472                 pcwl_p->pcwl_scanlist_timeout_id = 0;
 473         }
 474         if (pcwl_p->pcwl_connect_timeout_id != 0) {
 475                 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
 476                 pcwl_p->pcwl_connect_timeout_id = 0;
 477         }
 478         mutex_enter(&pcwl_p->pcwl_scanlist_lock);
 479         scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
 480         while (scan_item0) {
 481                 pcwl_delete_scan_item(pcwl_p, scan_item0);
 482                 scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
 483         }
 484         list_destroy(&pcwl_p->pcwl_scan_list);
 485         mutex_exit(&pcwl_p->pcwl_scanlist_lock);
 486         (void) mac_unregister(pcwl_p->pcwl_mh);
 487 
 488         if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
 489                 mutex_enter(&pcwl_p->pcwl_glock);
 490                 ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie);
 491                 ddi_regs_map_free(&pcwl_p->pcwl_handle);
 492                 ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
 493                 mutex_exit(&pcwl_p->pcwl_glock);
 494         } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
 495                 pcwl_unregister_cs(pcwl_p);
 496         }
 497         pcwl_destroy_locks(pcwl_p);
 498         ddi_remove_minor_node(dip, NULL);
 499         ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
 500         return (DDI_SUCCESS);
 501 }
 502 
 503 /*
 504  * card services and event handlers
 505  */
 506 static int
 507 pcwl_register_cs(dev_info_t *dip, pcwl_maci_t *pcwl_p)
 508 {
 509         int ret;
 510         client_reg_t cr;
 511         client_handle_t chdl; /* uint encoding of socket, function, client */
 512         get_status_t card_status;
 513         request_socket_mask_t sock_req;
 514 
 515         bzero(&cr, sizeof (cr));
 516         cr.Attributes   = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE;
 517         cr.EventMask    = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
 518             CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP |
 519             CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME |
 520             CS_EVENT_PM_SUSPEND | CS_EVENT_CLIENT_INFO;
 521         cr.event_callback_args.client_data = pcwl_p;
 522         cr.Version = CS_VERSION;
 523         cr.event_handler = (csfunction_t *)pcwl_ev_hdlr;
 524         cr.dip = dip;
 525         (void) strcpy(cr.driver_name, pcwl_name_str);
 526         if (ret = csx_RegisterClient(&chdl, &cr)) {
 527                 cmn_err(CE_WARN, "pcwl: RegisterClient failed %x\n", ret);
 528                 goto regcs_ret;
 529         }
 530         pcwl_p->pcwl_chdl = chdl;
 531 
 532         bzero(&card_status, sizeof (card_status));
 533         (void) csx_GetStatus(chdl, &card_status);
 534         PCWLDBG((CE_NOTE,
 535             "pcwl: register_cs: Sock=%x CState=%x SState=%x rState=%x\n",
 536             card_status.Socket, card_status.CardState,
 537             card_status.SocketState, card_status.raw_CardState));
 538         if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) {
 539                 /* card is not present, why are we attaching ? */
 540                 ret = CS_NO_CARD;
 541                 goto regcs_unreg;
 542         }
 543         cv_init(&pcwl_p->pcwl_cscv, NULL, CV_DRIVER, NULL);
 544         mutex_init(&pcwl_p->pcwl_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie);
 545         mutex_enter(&pcwl_p->pcwl_cslock);
 546         if (ret = csx_MapLogSocket(chdl, &pcwl_p->pcwl_log_sock)) {
 547                 cmn_err(CE_WARN, "pcwl: MapLogSocket failed %x\n", ret);
 548                 goto regcs_fail;
 549         }
 550         PCWLDBG((CE_NOTE,
 551             "pcwl: register_cs: LogSock=%x PhyAdapter=%x PhySock=%x\n",
 552             pcwl_p->pcwl_log_sock.LogSocket,
 553             pcwl_p->pcwl_log_sock.PhyAdapter,
 554             pcwl_p->pcwl_log_sock.PhySocket));
 555         /* turn on initialization events */
 556         sock_req.Socket = 0;
 557         sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
 558             CS_EVENT_REGISTRATION_COMPLETE;
 559         if (ret = csx_RequestSocketMask(chdl, &sock_req)) {
 560                 cmn_err(CE_WARN, "pcwl: RequestSocketMask failed %x\n", ret);
 561                 goto regcs_fail;
 562         }
 563         /* wait for and process card insertion events */
 564         while (!(pcwl_p->pcwl_flag & PCWL_CARD_READY))
 565                 cv_wait(&pcwl_p->pcwl_cscv, &pcwl_p->pcwl_cslock);
 566         mutex_exit(&pcwl_p->pcwl_cslock);
 567 
 568         pcwl_p->pcwl_flag |= PCWL_CS_REGISTERED;
 569         return (PCWL_SUCCESS);
 570 regcs_fail:
 571         mutex_destroy(&pcwl_p->pcwl_cslock);
 572         cv_destroy(&pcwl_p->pcwl_cscv);
 573 regcs_unreg:
 574         (void) csx_DeregisterClient(chdl);
 575 regcs_ret:
 576         pcwl_p->pcwl_flag &= ~PCWL_CS_REGISTERED;
 577         return (ret);
 578 }
 579 
 580 static void
 581 pcwl_unregister_cs(pcwl_maci_t *pcwl_p)
 582 {
 583         int ret;
 584         release_socket_mask_t mask;
 585         mask.Socket = pcwl_p->pcwl_socket;
 586 
 587         /*
 588          * The card service not registered means register_cs function
 589          * doesnot return TRUE. Then all the lelated resource has been
 590          * released in register_cs.
 591          */
 592         if (!(pcwl_p->pcwl_flag | PCWL_CS_REGISTERED))
 593                 return;
 594 
 595         if (ret = csx_ReleaseSocketMask(pcwl_p->pcwl_chdl, &mask))
 596                 cmn_err(CE_WARN, "pcwl: ReleaseSocket mask failed %x\n", ret);
 597 
 598         if (pcwl_p->pcwl_flag & PCWL_CARD_READY) {
 599                 pcwl_card_remove(pcwl_p);
 600                 pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
 601         }
 602         mutex_destroy(&pcwl_p->pcwl_cslock);
 603         cv_destroy(&pcwl_p->pcwl_cscv);
 604         if (ret = csx_DeregisterClient(pcwl_p->pcwl_chdl))
 605                 cmn_err(CE_WARN, "pcwl: Deregister failed %x\n", ret);
 606 }
 607 
 608 static void
 609 pcwl_destroy_locks(pcwl_maci_t *pcwl_p)
 610 {
 611         mutex_destroy(&pcwl_p->pcwl_txring.wl_tx_lock);
 612         mutex_destroy(&pcwl_p->pcwl_scanlist_lock);
 613         mutex_destroy(&pcwl_p->pcwl_glock);
 614 }
 615 
 616 static void
 617 pcwl_do_suspend(pcwl_maci_t *pcwl_p);
 618 
 619 static int
 620 pcwl_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
 621 {
 622         int ret = CS_SUCCESS;
 623         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg->client_data;
 624         client_info_t *ci_p = (client_info_t *)&arg->client_info;
 625 
 626         mutex_enter(&pcwl_p->pcwl_cslock);
 627         switch (event) {
 628         case CS_EVENT_CARD_INSERTION:
 629                 ret = pcwl_card_insert(pcwl_p);
 630                 cv_broadcast(&pcwl_p->pcwl_cscv);
 631                 break;
 632         case CS_EVENT_REGISTRATION_COMPLETE:
 633                 cv_broadcast(&pcwl_p->pcwl_cscv);
 634                 break;
 635         case CS_EVENT_CARD_REMOVAL:
 636                 if (priority & CS_EVENT_PRI_HIGH)
 637                         break;
 638                 pcwl_card_remove(pcwl_p);
 639                 cv_broadcast(&pcwl_p->pcwl_cscv);
 640                 break;
 641         case CS_EVENT_CLIENT_INFO:
 642                 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) !=
 643                     CS_CLIENT_INFO_SUBSVC_CS)
 644                         break;
 645 
 646                 ci_p->Revision = 0x0101;
 647                 ci_p->CSLevel = CS_VERSION;
 648                 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14);
 649                 (void) strcpy(ci_p->ClientName, PCWL_IDENT_STRING);
 650                 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
 651                 ci_p->Attributes |= CS_CLIENT_INFO_VALID;
 652                 break;
 653         case CS_EVENT_PM_SUSPEND:
 654                 pcwl_do_suspend(pcwl_p);
 655                 break;
 656         default:
 657                 ret = CS_UNSUPPORTED_EVENT;
 658                 break;
 659         }
 660         mutex_exit(&pcwl_p->pcwl_cslock);
 661         return (ret);
 662 }
 663 
 664 /*
 665  * assume card is already removed, don't touch the hardware
 666  */
 667 static void
 668 pcwl_do_suspend(pcwl_maci_t *pcwl_p)
 669 {
 670         int ret;
 671 
 672         if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
 673                 if (pcwl_p->pcwl_connect_timeout_id != 0) {
 674                         (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
 675                         pcwl_p->pcwl_connect_timeout_id = 0;
 676                 }
 677                 mutex_enter(&pcwl_p->pcwl_glock);
 678                 pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
 679                 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
 680                 /*
 681                  * A workaround here: If the card is in ad-hoc mode, the
 682                  * following scan will not work correctly, so any
 683                  * 'dladm connect-wifi' which need a scan first will not
 684                  * succeed. software reset the card here as a workround.
 685                  */
 686                 if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) &&
 687                     (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) {
 688                         (void) pcwl_reset_backend(pcwl_p);
 689                         (void) pcwl_init_nicmem(pcwl_p);
 690                         pcwl_start_locked(pcwl_p);
 691                 }
 692                 if (ret = pcwl_loaddef_rf(pcwl_p)) {
 693                         PCWLDBG((CE_WARN, "cfg_loaddef_err %d\n", ret));
 694                 }
 695                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
 696                         PCWLDBG((CE_WARN, "set enable cmd err\n"));
 697                 }
 698                 pcwl_delay(pcwl_p, 1000000);
 699                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
 700                         PCWLDBG((CE_WARN, "set disable cmd err\n"));
 701                 }
 702                 mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
 703                 mutex_exit(&pcwl_p->pcwl_glock);
 704         }
 705         pcwl_p->pcwl_flag |= PCWL_CARD_SUSPEND;
 706         PCWLDBG((CE_WARN, "pcwl: do suspend\n"));
 707 }
 708 
 709 
 710 static int
 711 pcwl_card_insert(pcwl_maci_t *pcwl_p)
 712 {
 713         int ret, hi, lo;
 714         tuple_t tuple;
 715         cisparse_t cisparse;
 716         io_req_t        io;
 717         irq_req_t       irq;
 718         config_req_t    cfg;
 719         cistpl_config_t config;
 720         cistpl_cftable_entry_t *tbl_p;
 721         register client_handle_t chdl = pcwl_p->pcwl_chdl;
 722         modify_config_t cfgmod;
 723 
 724         bzero(&tuple, sizeof (tuple));
 725         tuple.DesiredTuple = CISTPL_MANFID;
 726         if (ret = csx_GetFirstTuple(chdl, &tuple)) {
 727                 cmn_err(CE_WARN, "pcwl: get manufacture id failed %x\n", ret);
 728                 goto insert_ret;
 729         }
 730         bzero(&cisparse, sizeof (cisparse));
 731         if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) {
 732                 cmn_err(CE_WARN, "pcwl: parse manufacture id failed %x\n", ret);
 733                 goto insert_ret;
 734         }
 735 
 736         /*
 737          * verify manufacture ID
 738          */
 739         PCWLDBG((CE_NOTE, "pcwl insert: manufacturer_id=%x card=%x\n",
 740             cisparse.manfid.manf, cisparse.manfid.card));
 741         bzero(&tuple, sizeof (tuple));
 742         tuple.DesiredTuple = CISTPL_FUNCID;
 743         if (ret = csx_GetFirstTuple(chdl, &tuple)) {
 744                 cmn_err(CE_WARN, "pcwl: get function id failed %x\n", ret);
 745                 goto insert_ret;
 746         }
 747         bzero(&cisparse, sizeof (cisparse));
 748         if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) {
 749                 cmn_err(CE_WARN, "pcwl: parse function id failed %x\n", ret);
 750                 goto insert_ret;
 751         }
 752 
 753         /*
 754          * verify function ID
 755          */
 756         PCWLDBG((CE_NOTE, "insert:fun_id=%x\n", cisparse.funcid.function));
 757         bzero(&tuple, sizeof (tuple));
 758         tuple.DesiredTuple = CISTPL_CONFIG;
 759         if (ret = csx_GetFirstTuple(chdl, &tuple)) {
 760                 cmn_err(CE_WARN, "pcwl: get config failed %x\n", ret);
 761                 goto insert_ret;
 762         }
 763         bzero(&config, sizeof (config));
 764         if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) {
 765                 cmn_err(CE_WARN, "pcwl: parse config failed %x\n", ret);
 766                 goto insert_ret;
 767         }
 768         PCWLDBG((CE_NOTE,
 769             "pcwl: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n",
 770             config.present, config.nr, config.hr, config.regs[0],
 771             config.base, config.last));
 772         hi = 0;
 773         lo = (int)-1;           /* really big number */
 774         tbl_p = &cisparse.cftable;
 775         tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 776         for (tbl_p->index = 0; tbl_p->index <= config.hr; ) {
 777                 PCWLDBG((CE_NOTE, "pcwl insert:tuple idx=%x:\n", tbl_p->index));
 778                 if (ret = csx_GetNextTuple(chdl, &tuple)) {
 779                         cmn_err(CE_WARN, "pcwl: get cftable failed %x\n",
 780                             ret);
 781                         break;
 782                 }
 783                 bzero((caddr_t)&cisparse, sizeof (cisparse));
 784                 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) {
 785                         cmn_err(CE_WARN, "pcwl: parse cftable failed %x\n",
 786                             ret);
 787                         break;
 788                 }
 789                 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR &&
 790                     tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
 791                         if (tbl_p->pd.pd_vcc.avgI > hi) {
 792                                 hi = tbl_p->pd.pd_vcc.avgI;
 793                                 pcwl_p->pcwl_config_hi = tbl_p->index;
 794                         }
 795                         if (tbl_p->pd.pd_vcc.avgI < lo) {
 796                                 lo = tbl_p->pd.pd_vcc.avgI;
 797                                 pcwl_p->pcwl_config = tbl_p->index;
 798                         }
 799                 }
 800                 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) {
 801                         if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC)
 802                                 pcwl_p->pcwl_vcc = tbl_p->pd.pd_vcc.nomV;
 803                         if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO)
 804                                 pcwl_p->pcwl_iodecode = tbl_p->io.addr_lines;
 805                 }
 806         }
 807         PCWLDBG((CE_NOTE, "pcwl: insert:cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n",
 808             pcwl_p->pcwl_config_hi, pcwl_p->pcwl_config,
 809             pcwl_p->pcwl_vcc, pcwl_p->pcwl_iodecode));
 810         bzero(&io, sizeof (io));
 811         io.BasePort1.base = 0;
 812         io.NumPorts1 = 1 << pcwl_p->pcwl_iodecode;
 813         io.Attributes1 = IO_DATA_PATH_WIDTH_16;
 814         io.IOAddrLines = pcwl_p->pcwl_iodecode;
 815         if (ret = csx_RequestIO(chdl, &io)) {
 816                 cmn_err(CE_WARN, "pcwl: RequestIO failed %x\n", ret);
 817                 goto insert_ret;
 818         }
 819         pcwl_p->pcwl_port = io.BasePort1.handle;
 820         if (ret = ddi_add_softintr(DIP(pcwl_p), DDI_SOFTINT_HIGH,
 821             &pcwl_p->pcwl_softint_id, &pcwl_p->pcwl_ib_cookie, NULL,
 822             pcwl_intr, (caddr_t)pcwl_p)) {
 823                 cmn_err(CE_NOTE, "pcwl(pccard): add softintr failed\n");
 824                 goto insert_ret;
 825         }
 826         irq.Attributes = IRQ_TYPE_EXCLUSIVE;
 827         irq.irq_handler = ddi_intr_hilevel(DIP(pcwl_p), 0) ?
 828             (csfunction_t *)pcwl_intr_hi : (csfunction_t *)pcwl_intr;
 829         irq.irq_handler_arg = pcwl_p;
 830         if (ret = csx_RequestIRQ(pcwl_p->pcwl_chdl, &irq)) {
 831                 cmn_err(CE_WARN, "pcwl: RequestIRQ failed %x\n", ret);
 832                 goto un_io;
 833         }
 834         bzero(&cfg, sizeof (cfg));
 835         cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */
 836         cfg.Vcc = 50;
 837         cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO;
 838         cfg.ConfigBase = config.base;
 839         cfg.ConfigIndex = pcwl_p->pcwl_config;
 840         cfg.Status = CCSR_IO_IS_8;
 841         cfg.Present = config.present;
 842         pcwl_p->pcwl_flag |= PCWL_CARD_READY;
 843         if (ret = csx_RequestConfiguration(chdl, &cfg)) {
 844                 cmn_err(CE_WARN, "pcwl: RequestConfiguration failed %x\n", ret);
 845                 goto un_irq;
 846         }
 847 
 848         if (pcwl_p->pcwl_flag & PCWL_CARD_SUSPEND) {
 849                 mutex_enter(&pcwl_p->pcwl_glock);
 850                 (void) pcwl_reset_backend(pcwl_p);
 851                 /* turn on CS interrupt */
 852                 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
 853                     CONF_IRQ_CHANGE_VALID;
 854                 cfgmod.Vpp1 = 50;
 855                 cfgmod.Vpp2 = 50;
 856                 (void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod);
 857 
 858                 (void) pcwl_init_nicmem(pcwl_p);
 859                 pcwl_chip_type(pcwl_p);
 860                 (void) pcwl_loaddef_rf(pcwl_p);
 861                 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
 862                 pcwl_stop_locked(pcwl_p);       /* leaves interface down */
 863                 pcwl_p->pcwl_flag &= ~PCWL_CARD_SUSPEND;
 864                 mutex_exit(&pcwl_p->pcwl_glock);
 865         }
 866         if (pcwl_p->pcwl_flag & PCWL_CARD_PLUMBED) {
 867                 (void) pcwl_start(pcwl_p);
 868                 pcwl_p->pcwl_flag &= ~PCWL_CARD_PLUMBED;
 869         }
 870         return (CS_SUCCESS);
 871 un_irq:
 872         (void) csx_ReleaseIRQ(chdl, &irq);
 873 un_io:
 874         ddi_remove_softintr(pcwl_p->pcwl_softint_id);
 875         (void) csx_ReleaseIO(chdl, &io);
 876         pcwl_p->pcwl_port = 0;
 877 insert_ret:
 878         pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
 879         return (ret);
 880 
 881 }
 882 
 883 /*
 884  * assume card is already removed, don't touch the hardware
 885  */
 886 static void
 887 pcwl_card_remove(pcwl_maci_t *pcwl_p)
 888 {
 889         int ret;
 890         io_req_t io;
 891         irq_req_t irq;
 892 
 893         /*
 894          * The card not ready means Insert function doesnot return TRUE.
 895          * then the IO and IRQ has been released in Insert
 896          */
 897         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY))
 898                 return;
 899 
 900         if (pcwl_p->pcwl_connect_timeout_id != 0) {
 901                 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
 902                 pcwl_p->pcwl_connect_timeout_id = 0;
 903         }
 904 
 905         if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
 906                 pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
 907                 mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
 908         }
 909         mutex_enter(&pcwl_p->pcwl_glock);
 910         if (pcwl_p->pcwl_flag & PCWL_CARD_INTREN) {
 911                 pcwl_stop_locked(pcwl_p);
 912                 pcwl_p->pcwl_flag |= PCWL_CARD_PLUMBED;
 913         }
 914         pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
 915         mutex_exit(&pcwl_p->pcwl_glock);
 916         if (ret = csx_ReleaseConfiguration(pcwl_p->pcwl_chdl, NULL))
 917                 cmn_err(CE_WARN, "pcwl: ReleaseConfiguration failed %x\n", ret);
 918 
 919         bzero(&irq, sizeof (irq));
 920         if (ret = csx_ReleaseIRQ(pcwl_p->pcwl_chdl, &irq))
 921                 cmn_err(CE_WARN, "pcwl: ReleaseIRQ failed %x\n", ret);
 922 
 923         ddi_remove_softintr(pcwl_p->pcwl_softint_id);
 924 
 925         bzero(&io, sizeof (io));
 926         io.BasePort1.handle = pcwl_p->pcwl_port;
 927         io.NumPorts1 = 16;
 928         if (ret = csx_ReleaseIO(pcwl_p->pcwl_chdl, &io))
 929                 cmn_err(CE_WARN, "pcwl: ReleaseIO failed %x\n", ret);
 930 
 931         pcwl_p->pcwl_port = 0;
 932 }
 933 
 934 /*
 935  * mac operation interface routines
 936  */
 937 static int
 938 pcwl_start(void *arg)
 939 {
 940         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
 941 
 942         mutex_enter(&pcwl_p->pcwl_glock);
 943         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
 944                 mutex_exit(&pcwl_p->pcwl_glock);
 945                 return (PCWL_FAIL);
 946         }
 947         pcwl_start_locked(pcwl_p);
 948         mutex_exit(&pcwl_p->pcwl_glock);
 949         return (PCWL_SUCCESS);
 950 }
 951 
 952 static void
 953 pcwl_stop(void *arg)
 954 {
 955         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
 956 
 957         PCWLDBG((CE_NOTE, "pcwl_stop called\n"));
 958         mutex_enter(&pcwl_p->pcwl_glock);
 959         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
 960                 mutex_exit(&pcwl_p->pcwl_glock);
 961                 return;
 962         }
 963 
 964         pcwl_stop_locked(pcwl_p);
 965         mutex_exit(&pcwl_p->pcwl_glock);
 966         if (pcwl_p->pcwl_connect_timeout_id != 0) {
 967                 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
 968                 pcwl_p->pcwl_connect_timeout_id = 0;
 969         }
 970 }
 971 
 972 static int
 973 pcwl_saddr(void *arg, const uint8_t *macaddr)
 974 {
 975         int ret = PCWL_SUCCESS;
 976         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
 977 
 978         mutex_enter(&pcwl_p->pcwl_glock);
 979         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
 980                 ret = PCWL_FAIL;
 981                 goto done;
 982         }
 983         ether_copy(macaddr, pcwl_p->pcwl_mac_addr);
 984         if (pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
 985                 ret = PCWL_FAIL;
 986                 goto done;
 987         }
 988         if (pcwl_saddr_locked(pcwl_p)) {
 989                 ret = PCWL_FAIL;
 990                 goto done;
 991         }
 992         if (pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
 993                 ret = PCWL_FAIL;
 994         }
 995 done:
 996         if (ret)
 997                 cmn_err(CE_WARN, "pcwl set_mac_addr: failed\n");
 998         mutex_exit(&pcwl_p->pcwl_glock);
 999         return (ret);
1000 }
1001 
1002 static int
1003 pcwl_send(pcwl_maci_t *pcwl_p, mblk_t *mblk_p)
1004 {
1005         int i = 0;
1006         char *buf, *buf_p;
1007         wl_frame_t *frm_p;
1008         uint16_t pkt_len, ret;
1009         uint16_t xmt_id, ring_idx;
1010         struct ieee80211_frame *wh;
1011         struct ieee80211_llc *llc;
1012 
1013         mutex_enter(&pcwl_p->pcwl_glock);
1014         if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_LINKUP)) !=
1015             (PCWL_CARD_READY | PCWL_CARD_LINKUP)) {
1016                 mutex_exit(&pcwl_p->pcwl_glock);
1017                 freemsg(mblk_p);
1018                 return (PCWL_SUCCESS);          /* drop packet */
1019         }
1020         mutex_exit(&pcwl_p->pcwl_glock);
1021 
1022         if (pullupmsg(mblk_p, -1) == 0) {
1023                 freemsg(mblk_p);
1024                 return (PCWL_SUCCESS);          /* drop packet */
1025         }
1026         wh = (struct ieee80211_frame *)mblk_p->b_rptr;
1027         llc = (struct ieee80211_llc *)&wh[1];
1028 
1029         mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock);
1030         ring_idx = pcwl_p->pcwl_txring.wl_tx_prod;
1031         pcwl_p->pcwl_txring.wl_tx_prod = (ring_idx + 1) & (WL_XMT_BUF_NUM - 1);
1032 
1033         /*
1034          * check whether there is a xmt buffer available
1035          */
1036         while ((i < WL_XMT_BUF_NUM) &&
1037             (pcwl_p->pcwl_txring.wl_tx_ring[ring_idx])) {
1038                 ring_idx = pcwl_p->pcwl_txring.wl_tx_prod;
1039                 pcwl_p->pcwl_txring.wl_tx_prod =
1040                     (ring_idx + 1) & (WL_XMT_BUF_NUM - 1);
1041                 i++;
1042         }
1043         if (i == WL_XMT_BUF_NUM) {
1044                 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
1045                 mutex_enter(&pcwl_p->pcwl_glock);
1046                 pcwl_p->pcwl_reschedule_need = B_TRUE;
1047                 mutex_exit(&pcwl_p->pcwl_glock);
1048                 pcwl_p->pcwl_noxmtbuf++;
1049                 return (PCWL_FAIL);
1050         }
1051         xmt_id = pcwl_p->pcwl_txring.wl_tx_fids[ring_idx];
1052         pcwl_p->pcwl_txring.wl_tx_ring[ring_idx] = xmt_id;
1053         mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
1054 
1055         buf = kmem_zalloc(PCWL_NICMEM_SZ, KM_SLEEP);
1056         buf_p = (ulong_t)buf & 1 ? buf + 1 : buf;
1057         frm_p = (wl_frame_t *)buf_p;
1058 #ifdef DEBUG
1059         if (pcwl_debug & PCWL_DBG_SEND) {
1060                 cmn_err(CE_NOTE, "pcwl send: packet");
1061                 for (i = 0; i < MBLKL(mblk_p); i++)
1062                         cmn_err(CE_NOTE, "%x: %x\n", i,
1063                             *((unsigned char *)mblk_p->b_rptr + i));
1064         }
1065 #endif
1066         pkt_len = msgdsize(mblk_p);
1067         if (pkt_len > (PCWL_NICMEM_SZ - sizeof (wl_frame_t))) {
1068                 cmn_err(CE_WARN, "pcwl: send mblk is too long");
1069                 kmem_free(buf, PCWL_NICMEM_SZ);
1070                 freemsg(mblk_p);
1071                 return (PCWL_SUCCESS);          /* drop packet */
1072         }
1073         if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
1074             IEEE80211_FC1_DIR_TODS) {
1075                 kmem_free(buf, PCWL_NICMEM_SZ);
1076                 freemsg(mblk_p);
1077                 return (PCWL_SUCCESS);          /* drop packet */
1078         }
1079         bzero(frm_p, WL_802_11_HDRLEN);
1080 
1081         frm_p->wl_tx_ctl = WL_TXCNTL_SET;
1082         bcopy(wh->i_addr3, frm_p->wl_dst_addr, ETHERADDRL); /* dst macaddr */
1083         bcopy(wh->i_addr2, frm_p->wl_src_addr, ETHERADDRL); /* src macaddr */
1084         frm_p->wl_len = htons(pkt_len  - sizeof (*wh));
1085         bcopy(llc, &frm_p->wl_dat[0], pkt_len - sizeof (*wh));
1086         pkt_len = pkt_len - (sizeof (*wh) + sizeof (*llc)) +
1087             WL_802_11_HDRLEN;
1088         PCWLDBG((CE_NOTE, "send: DIX frmsz=%x pkt_len=%x\n",
1089             WL_802_11_HDRLEN, pkt_len));
1090 
1091         if (pkt_len & 1)    /* round up to 16-bit boundary and pad 0 */
1092                 buf_p[pkt_len++] = 0;
1093 
1094         ASSERT(pkt_len <= PCWL_NICMEM_SZ);
1095 #ifdef DEBUG
1096         if (pcwl_debug & PCWL_DBG_SEND) {
1097                 cmn_err(CE_NOTE, "pkt_len = %x\n", pkt_len);
1098                 for (i = 0; i < pkt_len; i++)
1099                         cmn_err(CE_NOTE, "%x: %x\n", i,
1100                             *((unsigned char *)buf + i));
1101         }
1102 #endif
1103         mutex_enter(&pcwl_p->pcwl_glock);
1104         ret = (WRCH1(pcwl_p, xmt_id, 0, (uint16_t *)buf_p, 0x2e) ||
1105             WRPKT(pcwl_p, xmt_id, 0x2e, (uint16_t *)(buf_p + 0x2e),
1106             pkt_len - 0x2e));
1107         if (ret) {
1108                 goto done;
1109         }
1110         PCWLDBG((CE_NOTE, "send: xmt_id=%x send=%x\n", xmt_id, pkt_len));
1111         (void) pcwl_set_cmd(pcwl_p, WL_CMD_TX | WL_RECLAIM, xmt_id);
1112 
1113 done:
1114         mutex_exit(&pcwl_p->pcwl_glock);
1115         kmem_free(buf, PCWL_NICMEM_SZ);
1116         freemsg(mblk_p);
1117         return (PCWL_SUCCESS);
1118 }
1119 
1120 static mblk_t *
1121 pcwl_tx(void *arg, mblk_t *mp)
1122 {
1123         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1124         mblk_t *next;
1125 
1126         ASSERT(mp != NULL);
1127         mutex_enter(&pcwl_p->pcwl_glock);
1128         if ((pcwl_p->pcwl_flag & (PCWL_CARD_LINKUP | PCWL_CARD_READY)) !=
1129             (PCWL_CARD_LINKUP | PCWL_CARD_READY)) {
1130                 mutex_exit(&pcwl_p->pcwl_glock);
1131                 freemsgchain(mp);
1132                 return (NULL);
1133         }
1134         mutex_exit(&pcwl_p->pcwl_glock);
1135         while (mp != NULL) {
1136                 next =  mp->b_next;
1137                 mp->b_next = NULL;
1138 
1139                 if (pcwl_send(pcwl_p, mp)) {
1140                         mp->b_next = next;
1141                         break;
1142                 }
1143                 mp = next;
1144         }
1145         return (mp);
1146 }
1147 
1148 static int
1149 pcwl_prom(void *arg, boolean_t on)
1150 {
1151         int ret = PCWL_SUCCESS;
1152         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1153 
1154         mutex_enter(&pcwl_p->pcwl_glock);
1155         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
1156                 ret = PCWL_FAIL;
1157                 goto done;
1158         }
1159 
1160         PCWLDBG((CE_NOTE, "pcwl_prom called %x\n", on));
1161 
1162         if (on)
1163                 pcwl_p->pcwl_rf.rf_promiscuous = 1;
1164         else
1165                 pcwl_p->pcwl_rf.rf_promiscuous = 0;
1166         if (ret = pcwl_fil_ltv(pcwl_p, 2, WL_RID_PROMISC,
1167             pcwl_p->pcwl_rf.rf_promiscuous)) {
1168                 ret = PCWL_FAIL;
1169         }
1170 done:
1171         if (ret)
1172                 cmn_err(CE_WARN, "pcwl promisc: failed\n");
1173         mutex_exit(&pcwl_p->pcwl_glock);
1174         return (ret);
1175 }
1176 
1177 static int
1178 pcwl_gstat(void *arg, uint_t statitem, uint64_t *val)
1179 {
1180         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1181         int ret = PCWL_SUCCESS;
1182         uint64_t *cntr_p = pcwl_p->pcwl_cntrs_s;
1183         uint16_t rate = 0;
1184         uint64_t speed;
1185 
1186         PCWLDBG((CE_NOTE, "pcwl_gstat called\n"));
1187         mutex_enter(&pcwl_p->pcwl_glock);
1188         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
1189                 ret = PCWL_FAIL;
1190                 goto done;
1191         }
1192 
1193         if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CUR_TX_RATE, &rate)) {
1194                 cmn_err(CE_WARN, "pcwl kstat: get speed failed\n");
1195                 ret = PCWL_FAIL;
1196                 goto done;
1197         }
1198         switch (pcwl_p->pcwl_chip_type) {
1199         case PCWL_CHIP_PRISMII:
1200                 switch (rate) {
1201                 case WL_SPEED_1Mbps_P2:         rate = 2;       break;
1202                 case WL_SPEED_2Mbps_P2:         rate = 4;       break;
1203                 case WL_SPEED_55Mbps_P2:        rate = 11;      break;
1204                 case WL_SPEED_11Mbps_P2:        rate = 22;      break;
1205                 default:                        rate = 0;       break;
1206                 }
1207                 speed = rate * 500000;
1208                 break;
1209         case PCWL_CHIP_LUCENT:
1210         default:
1211                 speed = rate * 1000000;
1212                 if (rate == 6)
1213                         speed = 5500000;
1214                 break;
1215         }
1216 
1217         switch (statitem) {
1218         case MAC_STAT_IFSPEED:
1219                 *val = speed;
1220                 break;
1221         case MAC_STAT_NOXMTBUF:
1222                 *val = pcwl_p->pcwl_noxmtbuf;
1223                 break;
1224         case MAC_STAT_NORCVBUF:
1225                 *val = cntr_p[WLC_RX_DISCARDS_NOBUF];
1226                 break;
1227         case MAC_STAT_IERRORS:
1228                 *val = 0;
1229                 break;
1230         case MAC_STAT_OERRORS:
1231                 *val = cntr_p[WLC_TX_DISCARDS] +
1232                     cntr_p[WLC_TX_DISCARDS_WRONG_SA];
1233                 break;
1234         case MAC_STAT_RBYTES:
1235                 *val = cntr_p[WLC_RX_UNICAST_OCTETS];
1236                 break;
1237         case MAC_STAT_IPACKETS:
1238                 *val = cntr_p[WLC_RX_UNICAST_FRAMES];
1239                 break;
1240         case MAC_STAT_OBYTES:
1241                 *val = cntr_p[WLC_TX_UNICAST_OCTETS];
1242                 break;
1243         case MAC_STAT_OPACKETS:
1244                 *val = cntr_p[WLC_TX_UNICAST_FRAMES];
1245                 break;
1246         case WIFI_STAT_TX_FAILED:
1247                 *val = cntr_p[WLC_TX_RETRY_LIMIT] +
1248                     cntr_p[WLC_TX_DEFERRED_XMITS];
1249                 break;
1250         case WIFI_STAT_TX_RETRANS:
1251                 *val = cntr_p[WLC_TX_SINGLE_RETRIES] +
1252                     cntr_p[WLC_TX_MULTI_RETRIES];
1253                 break;
1254         case WIFI_STAT_FCS_ERRORS:
1255                 *val = cntr_p[WLC_RX_FCS_ERRORS];
1256                 break;
1257         case WIFI_STAT_WEP_ERRORS:
1258                 *val = cntr_p[WLC_RX_WEP_CANT_DECRYPT];
1259                 break;
1260         case WIFI_STAT_MCAST_TX:
1261                 *val = cntr_p[WLC_TX_MULTICAST_FRAMES];
1262                 break;
1263         case WIFI_STAT_MCAST_RX:
1264                 *val = cntr_p[WLC_RX_MULTICAST_FRAMES];
1265                 break;
1266         case WIFI_STAT_TX_FRAGS:
1267                 *val = cntr_p[WLC_TX_FRAGMENTS];
1268                 break;
1269         case WIFI_STAT_RX_FRAGS:
1270                 *val =  cntr_p[WLC_RX_FRAGMENTS] +
1271                     cntr_p[WLC_RX_MSG_IN_MSG_FRAGS] +
1272                     cntr_p[WLC_RX_MSG_IN_BAD_MSG_FRAGS];
1273                 break;
1274         case WIFI_STAT_RTS_SUCCESS:
1275         case WIFI_STAT_RTS_FAILURE:
1276         case WIFI_STAT_ACK_FAILURE:
1277         case WIFI_STAT_RX_DUPS:
1278                 *val = 0;
1279                 break;
1280         default:
1281                 ret = ENOTSUP;
1282         }
1283 done:
1284         mutex_exit(&pcwl_p->pcwl_glock);
1285         return (ret);
1286 }
1287 
1288 static int
1289 pcwl_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p)
1290 {
1291         int ret = PCWL_SUCCESS;
1292         uint16_t i;
1293         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1294         uint16_t *mc_p = pcwl_p->pcwl_mcast;
1295 
1296         mutex_enter(&pcwl_p->pcwl_glock);
1297         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
1298                 ret = PCWL_FAIL;
1299                 goto done;
1300         }
1301 
1302         if (add) { /* enable multicast on eth_p, search for available entries */
1303                 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
1304                         if (!ether_cmp(eth_p, mc_p))
1305                                 break;
1306                 }
1307                 if (i < 16)  /* already part of the filter */
1308                         goto done;
1309                 mc_p = pcwl_p->pcwl_mcast;   /* reset mc_p for 2nd scan */
1310                 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
1311                         PCWLDBG((CE_NOTE, "smulti: mc[%x]=%s\n", i,
1312                             ether_sprintf((struct ether_addr *)mc_p)));
1313                         if (mc_p[0] == 0 && mc_p[1] == 0 && mc_p[2] == 0)
1314                                 break;
1315                 }
1316                 if (i >= 16) /* can't find a vacant entry */
1317                         goto done;
1318                 ether_copy(eth_p, mc_p);
1319         } else { /* disable multicast, locate the entry and clear it */
1320                 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
1321                         if (!ether_cmp(eth_p, mc_p))
1322                                 break;
1323                 }
1324                 if (i >= 16)
1325                         goto done;
1326                 mc_p[0] = 0;
1327                 mc_p[1] = 0;
1328                 mc_p[2] = 0;
1329         }
1330         /*
1331          * re-blow the entire 16 entries buffer
1332          */
1333         if (i = pcwl_put_ltv(pcwl_p, ETHERADDRL << 4, WL_RID_MCAST,
1334             pcwl_p->pcwl_mcast)) {
1335                 ret = PCWL_FAIL;
1336         }
1337 done:
1338         if (ret)
1339                 cmn_err(CE_WARN, "pcwl set multi addr: failed\n");
1340         mutex_exit(&pcwl_p->pcwl_glock);
1341         return (ret);
1342 }
1343 
1344 static uint_t
1345 pcwl_intr(caddr_t arg)
1346 {
1347         uint16_t stat;
1348         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1349 
1350         mutex_enter(&pcwl_p->pcwl_glock);
1351         if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) !=
1352             (PCWL_CARD_READY | PCWL_CARD_INTREN)) {
1353                 mutex_exit(&pcwl_p->pcwl_glock);
1354                 return (DDI_INTR_UNCLAIMED);
1355         }
1356         PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
1357         if (!(stat & WL_INTRS) || stat == WL_EV_ALL) {
1358                 mutex_exit(&pcwl_p->pcwl_glock);
1359                 return (DDI_INTR_UNCLAIMED);
1360         }
1361 
1362         PCWL_WRITE(pcwl_p, WL_INT_EN, 0);
1363         if (stat & WL_EV_RX) {
1364                 pcwl_rcv(pcwl_p);
1365                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX);
1366                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX);
1367         }
1368         if (stat & WL_EV_TX) {
1369                 if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) {
1370                         if (pcwl_p->pcwl_reschedule_need == B_TRUE) {
1371                                 mutex_exit(&pcwl_p->pcwl_glock);
1372                                 mac_tx_update(GLD3(pcwl_p));
1373                                 mutex_enter(&pcwl_p->pcwl_glock);
1374                                 pcwl_p->pcwl_reschedule_need = B_FALSE;
1375                         }
1376                 }
1377                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX);
1378                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX);
1379         }
1380         if (stat & WL_EV_ALLOC) {
1381                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC | 0x1000);
1382                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, 0x1000);
1383         }
1384         if (stat & WL_EV_INFO) {
1385                 pcwl_infodone(pcwl_p);
1386                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO);
1387                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO);
1388         }
1389         if (stat & WL_EV_TX_EXC) {
1390                 if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) {
1391                         if (pcwl_p->pcwl_reschedule_need == B_TRUE) {
1392                                 mutex_exit(&pcwl_p->pcwl_glock);
1393                                 mac_tx_update(GLD3(pcwl_p));
1394                                 mutex_enter(&pcwl_p->pcwl_glock);
1395                                 pcwl_p->pcwl_reschedule_need = B_FALSE;
1396                         }
1397                 }
1398                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC);
1399                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC);
1400         }
1401         if (stat & WL_EV_INFO_DROP) {
1402                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP);
1403                 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP);
1404         }
1405         PCWL_ENABLE_INTR(pcwl_p);
1406         mutex_exit(&pcwl_p->pcwl_glock);
1407 
1408         return (DDI_INTR_CLAIMED);
1409 }
1410 
1411 static uint_t
1412 pcwl_intr_hi(caddr_t arg)
1413 {
1414         uint16_t stat;
1415         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1416 
1417         mutex_enter(&pcwl_p->pcwl_glock);
1418         if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) !=
1419             (PCWL_CARD_READY | PCWL_CARD_INTREN)) {
1420                 mutex_exit(&pcwl_p->pcwl_glock);
1421                 return (DDI_INTR_UNCLAIMED);
1422         }
1423         PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
1424         if (!(stat & WL_INTRS) || stat == WL_EV_ALL) {
1425                 mutex_exit(&pcwl_p->pcwl_glock);
1426                 return (DDI_INTR_UNCLAIMED);
1427         }
1428         PCWL_WRITE(pcwl_p, WL_INT_EN, 0); /* disable interrupt without ack */
1429         mutex_exit(&pcwl_p->pcwl_glock);
1430         ddi_trigger_softintr(pcwl_p->pcwl_softint_id);
1431         return (DDI_INTR_CLAIMED);
1432 }
1433 
1434 /*
1435  * called at interrupt context to retrieve data from card
1436  */
1437 static void
1438 pcwl_rcv(pcwl_maci_t *pcwl_p)
1439 {
1440         uint16_t id, len, off, ret, frm_ctl;
1441         wl_frame_t frm;
1442         mblk_t *mp = allocb(PCWL_NICMEM_SZ, BPRI_MED);
1443         if (!mp)
1444                 return;
1445         ASSERT(mp->b_rptr == mp->b_wptr);
1446 
1447         PCWL_READ(pcwl_p, WL_RX_FID, id);
1448         PCWL_WRITE(pcwl_p, WL_RX_FID, 0);
1449         if (id == WL_INVALID_FID) {
1450                 PCWLDBG((CE_NOTE, "pcwl rcv: get rx_fid failed\n"));
1451                 ret = PCWL_FAIL;
1452                 goto done;
1453         }
1454         if (ret = RDCH0(pcwl_p, id, 0, (uint16_t *)&frm, sizeof (frm))) {
1455                 PCWLDBG((CE_NOTE, "pcwl rcv: read frm failed %x\n", ret));
1456                 goto done;
1457         }
1458         if (frm.wl_status & WL_STAT_ERRSTAT) {
1459                 PCWLDBG((CE_NOTE, "pcwl rcv: errstat %x\n", frm.wl_status));
1460                 ret = frm.wl_status;
1461                 goto done;
1462         }
1463         PCWLDBG((CE_NOTE, "pcwl rcv: frame type %x\n", frm.wl_status));
1464 #ifdef DEBUG
1465         if (pcwl_debug & PCWL_DBG_RCV) {
1466                 int i;
1467                 cmn_err(CE_NOTE, "pcwl rcv: frm header\n");
1468                 for (i = 0; i < WL_802_11_HDRLEN; i++)
1469                         cmn_err(CE_NOTE, "%x: %x\n", i,
1470                             *((uint8_t *)&frm + i));
1471         }
1472 #endif
1473         len = frm.wl_dat_len;
1474         /*
1475          * this driver deal with WEP by itself. so plugin always thinks no wep.
1476          */
1477         frm.wl_frame_ctl &= ~(IEEE80211_FC1_WEP << 8);
1478         frm_ctl = frm.wl_frame_ctl;
1479         switch (frm.wl_status) {
1480         case WL_STAT_1042:
1481         case WL_STAT_TUNNEL:
1482         case WL_STAT_WMP_MSG:
1483                 PCWL_SWAP16((uint16_t *)&frm.wl_frame_ctl,
1484                     sizeof (struct ieee80211_frame));
1485                 /*
1486                  * discard those frames which are not from the AP we connect or
1487                  * without 'ap->sta' direction
1488                  */
1489                 if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_BSS) &&
1490                     ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) !=
1491                     IEEE80211_FC1_DIR_FROMDS) ||
1492                     bcmp(pcwl_p->pcwl_bssid, frm.wl_addr2, 6) != 0)) {
1493                         ret = PCWL_FAIL;
1494                         goto done;
1495                 }
1496 
1497                 bcopy(&frm.wl_frame_ctl, mp->b_wptr,
1498                     sizeof (struct ieee80211_frame));
1499                 mp->b_wptr += sizeof (struct ieee80211_frame);
1500 
1501                 PCWL_SWAP16((uint16_t *)&frm.wl_dat[0],
1502                     sizeof (struct ieee80211_llc));
1503                 bcopy(&frm.wl_dat[0], mp->b_wptr,
1504                     sizeof (struct ieee80211_llc));
1505                 mp->b_wptr += sizeof (struct ieee80211_llc);
1506 
1507                 len -= (2 + WL_SNAPHDR_LEN);
1508                 off = WL_802_11_HDRLEN;
1509                 break;
1510         default:
1511                 PCWLDBG((CE_NOTE, "pcwl rcv: incorrect pkt\n"));
1512                 break;
1513         }
1514         if (len > MBLKSIZE(mp)) {
1515                 PCWLDBG((CE_NOTE, "pcwl rcv: oversz pkt %x\n", len));
1516                 ret = PCWL_FAIL;
1517                 goto done;
1518         }
1519         if (len & 1)
1520                 len++;
1521         ret = RDPKT(pcwl_p, id, off, (uint16_t *)mp->b_wptr, len);
1522 done:
1523         if (ret) {
1524                 PCWLDBG((CE_NOTE, "pcwl rcv: rd data %x\n", ret));
1525                 freemsg(mp);
1526                 return;
1527         }
1528         mp->b_wptr = mp->b_wptr + len;
1529 #ifdef DEBUG
1530         if (pcwl_debug & PCWL_DBG_RCV) {
1531                 int i;
1532                 cmn_err(CE_NOTE, "pcwl rcv: len=0x%x\n", len);
1533                 for (i = 0; i < len+14; i++)
1534                         cmn_err(CE_NOTE, "%x: %x\n", i,
1535                             *((uint8_t *)mp->b_rptr + i));
1536         }
1537 #endif
1538         mutex_exit(&pcwl_p->pcwl_glock);
1539         mac_rx(GLD3(pcwl_p), NULL, mp);
1540         mutex_enter(&pcwl_p->pcwl_glock);
1541 }
1542 
1543 static uint32_t
1544 pcwl_txdone(pcwl_maci_t *pcwl_p)
1545 {
1546         uint16_t fid, i;
1547         PCWL_READ(pcwl_p, WL_ALLOC_FID, fid);
1548         PCWL_WRITE(pcwl_p, WL_ALLOC_FID, 0);
1549 
1550         mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock);
1551         for (i = 0; i < WL_XMT_BUF_NUM; i++) {
1552                 if (fid == pcwl_p->pcwl_txring.wl_tx_ring[i]) {
1553                         pcwl_p->pcwl_txring.wl_tx_ring[i] = 0;
1554                         break;
1555                 }
1556         }
1557         pcwl_p->pcwl_txring.wl_tx_cons =
1558             (pcwl_p->pcwl_txring.wl_tx_cons + 1) & (WL_XMT_BUF_NUM - 1);
1559         mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
1560         if (i == WL_XMT_BUF_NUM)
1561                 return (PCWL_FAIL);
1562         return (PCWL_SUCCESS);
1563 
1564 }
1565 
1566 static void
1567 pcwl_infodone(pcwl_maci_t *pcwl_p)
1568 {
1569         uint16_t id, ret, i;
1570         uint16_t linkStatus[2];
1571         uint16_t linkStat;
1572         wifi_data_t wd = { 0 };
1573 
1574         PCWL_READ(pcwl_p, WL_INFO_FID, id);
1575         if (id == WL_INVALID_FID) {
1576                 cmn_err(CE_WARN, "pcwl infodone: read info_fid failed\n");
1577                 return;
1578         }
1579         if (ret = RDCH0(pcwl_p, id, 0, linkStatus, sizeof (linkStatus))) {
1580                 PCWLDBG((CE_WARN, "pcwl infodone read infoFrm failed %x\n",
1581                     ret));
1582                 return;
1583         }
1584         PCWLDBG((CE_NOTE, "pcwl infodone: Frame length= %x, Frame Type = %x\n",
1585             linkStatus[0], linkStatus[1]));
1586 
1587         switch (linkStatus[1]) {
1588         case WL_INFO_LINK_STAT:
1589                 (void) RDCH0(pcwl_p, id, sizeof (linkStatus), &linkStat,
1590                     sizeof (linkStat));
1591                 PCWLDBG((CE_NOTE, "pcwl infodone: link status=%x\n", linkStat));
1592                 if (!(pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) &&
1593                     linkStat == WL_LINK_CONNECT) {
1594 #ifdef DEBUG
1595                 if (pcwl_debug & PCWL_DBG_LINKINFO)
1596                         cmn_err(CE_NOTE, "pcwl: Link up \n");
1597 #endif
1598                         pcwl_p->pcwl_flag |= PCWL_CARD_LINKUP;
1599                         mutex_exit(&pcwl_p->pcwl_glock);
1600                         if (pcwl_p->pcwl_connect_timeout_id != 0) {
1601                                 (void) untimeout(pcwl_p->
1602                                     pcwl_connect_timeout_id);
1603                                 pcwl_p->pcwl_connect_timeout_id = 0;
1604                         }
1605                         mutex_enter(&pcwl_p->pcwl_glock);
1606                         mac_link_update(GLD3(pcwl_p), LINK_STATE_UP);
1607                         (void) pcwl_get_ltv(pcwl_p, 6,
1608                             WL_RID_BSSID, (uint16_t *)pcwl_p->pcwl_bssid);
1609                         PCWL_SWAP16((uint16_t *)pcwl_p->pcwl_bssid, 6);
1610                         pcwl_get_rssi(pcwl_p);
1611                         bcopy(pcwl_p->pcwl_bssid, wd.wd_bssid, 6);
1612                         wd.wd_secalloc = WIFI_SEC_NONE;
1613                         wd.wd_opmode = IEEE80211_M_STA;
1614                         (void) mac_pdata_update(pcwl_p->pcwl_mh, &wd,
1615                             sizeof (wd));
1616                 }
1617                 if ((pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) &&
1618                     ((linkStat == WL_LINK_DISCONNECT) ||
1619                     (linkStat == WL_LINK_AP_OOR))) {
1620 #ifdef DEBUG
1621                 if (pcwl_debug & PCWL_DBG_LINKINFO)
1622                         cmn_err(CE_NOTE, "pcwl: Link down \n");
1623 #endif
1624                         PCWLDBG((CE_NOTE, "pcwl infodone: link status = %d\n",
1625                             linkStat));
1626                         pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
1627                         if (linkStat == WL_LINK_AP_OOR)
1628                                 pcwl_p->pcwl_connect_timeout_id =
1629                                     timeout(pcwl_connect_timeout,
1630                                     pcwl_p, drv_usectohz(1000));
1631                         mutex_exit(&pcwl_p->pcwl_glock);
1632                         mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
1633                         mutex_enter(&pcwl_p->pcwl_glock);
1634                 }
1635                 break;
1636         case WL_INFO_SCAN_RESULTS:
1637         case WL_INFO_HSCAN_RESULTS:
1638                 pcwl_ssid_scan(pcwl_p, id, linkStatus[0], linkStatus[1]);
1639                         break;
1640         case WL_INFO_COUNTERS:
1641                 linkStatus[0]--;
1642                 if (linkStatus[0] > WLC_STAT_CNT) {
1643                         linkStatus[0] = MIN(linkStatus[0], WLC_STAT_CNT);
1644                 }
1645                 (void) RDCH0(pcwl_p, id, sizeof (linkStatus),
1646                     pcwl_p->pcwl_cntrs_t, linkStatus[0]<<1);
1647                 /*
1648                  * accumulate all the statistics items for kstat use.
1649                  */
1650                 for (i = 0; i < WLC_STAT_CNT; i++)
1651                         pcwl_p->pcwl_cntrs_s[i] += pcwl_p->pcwl_cntrs_t[i];
1652                 break;
1653         default:
1654                 break;
1655         }
1656 }
1657 
1658 static uint16_t
1659 pcwl_set_cmd(pcwl_maci_t *pcwl_p, uint16_t cmd, uint16_t param)
1660 {
1661         int i;
1662         uint16_t stat;
1663 
1664         if (((cmd == WL_CMD_ENABLE) &&
1665             ((pcwl_p->pcwl_flag & PCWL_ENABLED) != 0)) ||
1666             ((cmd == WL_CMD_DISABLE) &&
1667             ((pcwl_p->pcwl_flag & PCWL_ENABLED) == 0)))
1668                 return (PCWL_SUCCESS);
1669 
1670         for (i = 0; i < WL_TIMEOUT; i++) {
1671                 PCWL_READ(pcwl_p, WL_COMMAND, stat);
1672                 if (stat & WL_CMD_BUSY) {
1673                         drv_usecwait(1);
1674                 } else {
1675                         break;
1676                 }
1677         }
1678         if (i == WL_TIMEOUT) {
1679                 cmn_err(CE_WARN, "pcwl: setcmd %x, %x timeout %x due to "
1680                     "busy bit\n", cmd, param, stat);
1681                 return (PCWL_TIMEDOUT_CMD);
1682         }
1683 
1684         PCWL_WRITE(pcwl_p, WL_PARAM0, param);
1685         PCWL_WRITE(pcwl_p, WL_PARAM1, 0);
1686         PCWL_WRITE(pcwl_p, WL_PARAM2, 0);
1687         PCWL_WRITE(pcwl_p, WL_COMMAND, cmd);
1688         if (cmd == WL_CMD_INI)
1689                 drv_usecwait(100000); /* wait .1 sec */
1690 
1691         for (i = 0; i < WL_TIMEOUT; i++) {
1692                 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
1693                 if (!(stat & WL_EV_CMD)) {
1694                         drv_usecwait(1);
1695                 } else {
1696                         break;
1697                 }
1698         }
1699         if (i == WL_TIMEOUT) {
1700                 cmn_err(CE_WARN, "pcwl: setcmd %x,%x timeout %x\n",
1701                     cmd, param, stat);
1702                 if (stat & (WL_EV_ALLOC | WL_EV_RX))
1703                         PCWL_WRITE(pcwl_p, WL_EVENT_ACK, stat);
1704                 return (PCWL_TIMEDOUT_CMD);
1705         }
1706         PCWL_READ(pcwl_p, WL_STATUS, stat);
1707         PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_CMD);
1708         if (stat & WL_STAT_CMD_RESULT) { /* err in feedback status */
1709                 cmn_err(CE_WARN, "pcwl: set_cmd %x,%x failed %x\n",
1710                     cmd, param, stat);
1711                 return (PCWL_FAILURE_CMD);
1712         }
1713         if (cmd == WL_CMD_ENABLE)
1714                 pcwl_p->pcwl_flag |= PCWL_ENABLED;
1715         if (cmd == WL_CMD_DISABLE)
1716                 pcwl_p->pcwl_flag &= (~PCWL_ENABLED);
1717         return (PCWL_SUCCESS);
1718 }
1719 
1720 static uint16_t
1721 pcwl_set_ch(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t channel)
1722 {
1723         int i;
1724         uint16_t stat, select, offset;
1725 
1726         if (channel) {
1727                 select = WL_SEL1;
1728                 offset = WL_OFF1;
1729         } else {
1730                 select = WL_SEL0;
1731                 offset = WL_OFF0;
1732         }
1733         PCWL_WRITE(pcwl_p, select, type);
1734         PCWL_WRITE(pcwl_p, offset, off);
1735         for (stat = 0, i = 0; i < WL_TIMEOUT; i++) {
1736                 PCWL_READ(pcwl_p, offset, stat);
1737                 if (!(stat & (WL_OFF_BUSY|WL_OFF_ERR)))
1738                         break;
1739                 else {
1740                         drv_usecwait(1);
1741                 }
1742         }
1743         if (i == WL_TIMEOUT) {
1744                 cmn_err(CE_WARN, "set_ch%d %x,%x failed %x\n",
1745                     channel, type, off, stat);
1746                 return (PCWL_TIMEDOUT_TARGET);
1747         }
1748         return (PCWL_SUCCESS);
1749 }
1750 
1751 static uint16_t
1752 pcwl_get_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p)
1753 {
1754         uint16_t stat;
1755 
1756         ASSERT(!(len & 1));
1757         len >>= 1;        /* convert bytes to 16-bit words */
1758 
1759         /*
1760          * 1. select read mode
1761          */
1762         if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS | WL_ACCESS_READ, type))
1763                 return (stat);
1764 
1765         /*
1766          * 2. select Buffer Access Path (channel) 1 for PIO
1767          */
1768         if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
1769                 return (stat);
1770 
1771         /*
1772          * 3. read length
1773          */
1774         PCWL_READ(pcwl_p, WL_DATA1, stat);
1775         if (stat != (len + 1)) {
1776                 PCWLDBG((CE_NOTE, "get_ltv 0x%x expected 0x%x+1, got 0x%x\n",
1777                     type, (len + 1) << 1, stat));
1778                 stat = (stat >> 1) - 1;
1779                 len = MIN(stat, len);
1780         }
1781 
1782         /*
1783          * 4. read type
1784          */
1785         PCWL_READ(pcwl_p, WL_DATA1, stat);
1786         if (stat != type)
1787                 return (PCWL_BADTYPE);
1788 
1789         /*
1790          * 5. read value
1791          */
1792         for (stat = 0; stat < len; stat++, val_p++) {
1793                 PCWL_READ_P(pcwl_p, WL_DATA1, val_p, 1);
1794         }
1795         return (PCWL_SUCCESS);
1796 }
1797 
1798 static uint16_t
1799 pcwl_fil_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t val)
1800 {
1801         uint16_t stat;
1802 
1803         ASSERT(!(len & 1));
1804 
1805         /*
1806          * 1. select Buffer Access Path (channel) 1 for PIO
1807          */
1808         if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
1809                 return (stat);
1810 
1811         /*
1812          * 2. write length
1813          */
1814         len >>= 1;                /* convert bytes to 16-bit words */
1815         stat = len + 1;         /* 1 extra word */
1816         PCWL_WRITE(pcwl_p, WL_DATA1, stat);
1817 
1818         /*
1819          * 3. write type
1820          */
1821         PCWL_WRITE(pcwl_p, WL_DATA1, type);
1822 
1823         /*
1824          * 4. fill value
1825          */
1826         for (stat = 0; stat < len; stat++) {
1827                 PCWL_WRITE(pcwl_p, WL_DATA1, val);
1828         }
1829 
1830         /*
1831          * 5. select write mode
1832          */
1833         return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type));
1834 }
1835 
1836 static uint16_t
1837 pcwl_put_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p)
1838 {
1839         uint16_t stat;
1840 
1841         ASSERT(!(len & 1));
1842 
1843         /*
1844          * 1. select Buffer Access Path (channel) 1 for PIO
1845          */
1846         if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
1847                 return (stat);
1848 
1849         /*
1850          * 2. write length
1851          */
1852         len >>= 1;                /* convert bytes to 16-bit words */
1853         stat = len + 1;         /* 1 extra word */
1854         PCWL_WRITE(pcwl_p, WL_DATA1, stat);
1855 
1856         /*
1857          * 3. write type
1858          */
1859         PCWL_WRITE(pcwl_p, WL_DATA1, type);
1860 
1861         /*
1862          * 4. write value
1863          */
1864         for (stat = 0; stat < len; stat++, val_p++) {
1865                 PCWL_WRITE_P(pcwl_p, WL_DATA1, val_p, 1);
1866         }
1867 
1868         /*
1869          * 5. select write mode
1870          */
1871         return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type));
1872 }
1873 
1874 #define PCWL_COMPSTR_LEN        34
1875 static uint16_t
1876 pcwl_put_str(pcwl_maci_t *pcwl_p, uint16_t type, char *str_p)
1877 {
1878         uint16_t buf[PCWL_COMPSTR_LEN / 2];
1879         uint8_t str_len = strlen(str_p);
1880 
1881         bzero(buf, PCWL_COMPSTR_LEN);
1882         buf[0] = str_len;
1883         bcopy(str_p, (caddr_t)(buf + 1), str_len);
1884         PCWLDBG((CE_NOTE, "put_str: buf[0]=%x buf=%s\n",
1885             buf[0], (caddr_t)(buf + 1)));
1886         PCWL_SWAP16(buf + 1, PCWL_COMPSTR_LEN - 2);
1887         return (pcwl_put_ltv(pcwl_p, PCWL_COMPSTR_LEN, type, buf));
1888 }
1889 
1890 /*ARGSUSED*/
1891 static uint16_t
1892 pcwl_rdch0(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p,
1893         int len, int order)
1894 {
1895         uint16_t o;
1896         ASSERT(!(len & 1));
1897         /*
1898          * It seems that for PrismII chip, frequently overlap use of path0
1899          * and path1 may hang the hardware. So for PrismII chip, just use
1900          * path1. Test proves this workaround is OK.
1901          */
1902         if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
1903                 if (type = pcwl_set_ch(pcwl_p, type, off, 1))
1904                         return (type);
1905                 o = WL_DATA1;
1906         } else {
1907                 if (type = pcwl_set_ch(pcwl_p, type, off, 0))
1908                         return (type);
1909                 o = WL_DATA0;
1910         }
1911         len >>= 1;
1912         for (off = 0; off < len; off++, buf_p++) {
1913                 PCWL_READ_P(pcwl_p, o, buf_p, order);
1914         }
1915         return (PCWL_SUCCESS);
1916 }
1917 
1918 /*ARGSUSED*/
1919 static uint16_t
1920 pcwl_wrch1(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p,
1921         int len, int order)
1922 {
1923         ASSERT(!(len & 1));
1924         if (type = pcwl_set_ch(pcwl_p, type, off, 1))
1925                 return (type);
1926         len >>= 1;
1927         for (off = 0; off < len; off++, buf_p++) {
1928                 PCWL_WRITE_P(pcwl_p, WL_DATA1, buf_p, order);
1929         }
1930         return (PCWL_SUCCESS);
1931 }
1932 
1933 static uint16_t
1934 pcwl_alloc_nicmem(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t *id_p)
1935 {
1936         int i;
1937         uint16_t stat;
1938 
1939         len = ((len + 1) >> 1) << 1;        /* round up to 16-bit boundary */
1940 
1941         if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ALLOC_MEM, len))
1942                 return (stat);
1943         for (stat = 0, i = 0; i < WL_TIMEOUT; i++) {
1944                 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
1945                 if (stat & WL_EV_ALLOC)
1946                         break;
1947                 else
1948                         drv_usecwait(1);
1949         }
1950         if (i == WL_TIMEOUT)
1951                 return (PCWL_TIMEDOUT_ALLOC);
1952         PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC);
1953         PCWL_READ(pcwl_p, WL_ALLOC_FID, stat);
1954         *id_p = stat;
1955 
1956         /*
1957          * zero fill the allocated NIC mem - sort of pcwl_fill_ch
1958          */
1959         (void) pcwl_set_ch(pcwl_p, stat, 0, 1);
1960 
1961         for (len >>= 1, stat = 0; stat < len; stat++) {
1962                 PCWL_WRITE(pcwl_p, WL_DATA1, 0);
1963         }
1964         return (PCWL_SUCCESS);
1965 }
1966 
1967 static int
1968 pcwl_add_scan_item(pcwl_maci_t *pcwl_p, wl_scan_result_t s)
1969 {
1970         wl_scan_list_t *scan_item;
1971 
1972         scan_item = kmem_zalloc(sizeof (wl_scan_list_t), KM_SLEEP);
1973         if (scan_item == NULL) {
1974                 cmn_err(CE_WARN, "pcwl add_scan_item: zalloc failed\n");
1975                 return (PCWL_FAIL);
1976         }
1977         scan_item->wl_val = s;
1978         scan_item->wl_timeout = WL_SCAN_TIMEOUT_MAX;
1979         list_insert_tail(&pcwl_p->pcwl_scan_list, scan_item);
1980         pcwl_p->pcwl_scan_num++;
1981         return (PCWL_SUCCESS);
1982 }
1983 
1984 static void
1985 pcwl_delete_scan_item(pcwl_maci_t *pcwl_p, wl_scan_list_t *s)
1986 {
1987         list_remove(&pcwl_p->pcwl_scan_list, s);
1988         kmem_free(s, sizeof (*s));
1989         pcwl_p->pcwl_scan_num--;
1990 }
1991 
1992 static void
1993 pcwl_scanlist_timeout(void *arg)
1994 {
1995         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1996         wl_scan_list_t *scan_item0, *scan_item1;
1997 
1998         mutex_enter(&pcwl_p->pcwl_scanlist_lock);
1999         scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
2000         for (; scan_item0; ) {
2001                 PCWLDBG((CE_NOTE, "ssid = %s\n",
2002                     scan_item0->wl_val.wl_srt_ssid));
2003                 PCWLDBG((CE_NOTE, "timeout left: %ds",
2004                     scan_item0->wl_timeout));
2005                 scan_item1 = list_next(&pcwl_p->pcwl_scan_list, scan_item0);
2006                 if (scan_item0->wl_timeout == 0) {
2007                         pcwl_delete_scan_item(pcwl_p, scan_item0);
2008                 } else {
2009                         scan_item0->wl_timeout--;
2010                 }
2011                 scan_item0 = scan_item1;
2012         }
2013         mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2014         pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout,
2015             pcwl_p, drv_usectohz(1000000));
2016 }
2017 
2018 static void
2019 pcwl_get_rssi(pcwl_maci_t *pcwl_p)
2020 {
2021         wl_scan_list_t *scan_item0;
2022         uint16_t cq[3];
2023 
2024         bzero(cq, sizeof (cq));
2025         mutex_enter(&pcwl_p->pcwl_scanlist_lock);
2026         scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
2027         for (; scan_item0; ) {
2028                 if (bcmp(scan_item0->wl_val.wl_srt_bssid,
2029                     pcwl_p->pcwl_bssid, 6) == 0) {
2030                         pcwl_p->pcwl_rssi = scan_item0->wl_val.wl_srt_sl;
2031                 }
2032                 scan_item0 = list_next(&pcwl_p->pcwl_scan_list, scan_item0);
2033         }
2034         mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2035         if (!pcwl_p->pcwl_rssi) {
2036                 (void) pcwl_get_ltv(pcwl_p, 6, WL_RID_COMMQUAL, cq);
2037                 pcwl_p->pcwl_rssi = cq[1];
2038         }
2039 }
2040 
2041 /*
2042  * Note:
2043  * PrismII chipset has 2 extra space for the reason why scan is initiated
2044  */
2045 static void
2046 pcwl_ssid_scan(pcwl_maci_t *pcwl_p, uint16_t fid, uint16_t flen, uint16_t stype)
2047 {
2048         uint16_t stat;
2049         uint16_t ssidNum, i;
2050         uint16_t off, szbuf;
2051         uint16_t tmp[2];
2052         wl_scan_list_t *scan_item0;
2053         uint32_t check_num;
2054         uint8_t bssid_t[6];
2055 
2056         wl_scan_result_t sctbl;
2057 
2058         off = sizeof (uint16_t) * 2;
2059         switch (pcwl_p->pcwl_chip_type) {
2060         case PCWL_CHIP_PRISMII:
2061                 (void) RDCH0(pcwl_p, fid, off, tmp, 4);
2062                 off += 4;
2063                 szbuf = (stype == WL_INFO_SCAN_RESULTS ? 31 : 32);
2064                 PCWLDBG((CE_NOTE, "pcwl ssid_scan: PRISM chip\n"));
2065                 break;
2066         case PCWL_CHIP_LUCENT:
2067                 PCWLDBG((CE_NOTE, "pcwl ssid_scan LUCENT chip\n"));
2068         default:
2069                 szbuf = 25;
2070         }
2071 
2072         flen = flen + 1 - (off >> 1);
2073         ssidNum = flen/szbuf;
2074         ssidNum = min(WL_SRT_MAX_NUM, ssidNum);
2075 
2076         PCWLDBG((CE_NOTE, "pcwl: ssid_scan frame length = %d\n", flen));
2077 
2078         PCWLDBG((CE_NOTE, "pcwl ssid_scan: %d ssid(s) available", ssidNum));
2079 
2080         bzero(bssid_t, sizeof (bssid_t));
2081         for (i = 0; i < ssidNum; i++) {
2082                 (void) RDCH0(pcwl_p, fid, off, (uint16_t *)&sctbl, 2*szbuf);
2083 
2084 #ifdef DEBUG
2085                 if (pcwl_debug & PCWL_DBG_INFO) {
2086                         int j;
2087                         for (j = 0; j < sizeof (sctbl); j++)
2088                                 cmn_err(CE_NOTE, "%d: %x\n", j,
2089                                     *((uint8_t *)&sctbl + j));
2090                 }
2091 #endif
2092 
2093                 off += (szbuf << 1);
2094                 stat = min(sctbl.wl_srt_ssidlen, 31);
2095                 PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_bssid), 6);
2096                 PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_ssid), stat);
2097                 sctbl.wl_srt_ssid[stat] = '\0';
2098                 sctbl.wl_srt_sl &= 0x7f;
2099 
2100                 /*
2101                  * sometimes, those empty items are recorded by hardware,
2102                  * this is wrong, just ignore those items here.
2103                  */
2104                 if (bcmp(sctbl.wl_srt_bssid,
2105                     bssid_t, 6) == 0) {
2106                         continue;
2107                 }
2108                 if (bcmp(sctbl.wl_srt_bssid,
2109                     pcwl_p->pcwl_bssid, 6) == 0) {
2110                         pcwl_p->pcwl_rssi = sctbl.wl_srt_sl;
2111                 }
2112                 /*
2113                  * save/update the scan item in scanlist
2114                  */
2115                 mutex_enter(&pcwl_p->pcwl_scanlist_lock);
2116                 check_num = 0;
2117                 scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
2118                 if (scan_item0 == NULL) {
2119                         if (pcwl_add_scan_item(pcwl_p, sctbl)
2120                             != 0) {
2121                                 mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2122                                 return;
2123                         }
2124                 }
2125                 for (; scan_item0; ) {
2126                         if (bcmp(sctbl.wl_srt_bssid,
2127                             scan_item0->wl_val.wl_srt_bssid, 6) == 0) {
2128                                 scan_item0->wl_val = sctbl;
2129                                 scan_item0->wl_timeout = WL_SCAN_TIMEOUT_MAX;
2130                                 break;
2131                         } else {
2132                                 check_num++;
2133                         }
2134                         scan_item0 = list_next(&pcwl_p->pcwl_scan_list,
2135                             scan_item0);
2136                 }
2137                 if (check_num == pcwl_p->pcwl_scan_num) {
2138                         if (pcwl_add_scan_item(pcwl_p, sctbl)
2139                             != 0) {
2140                                 mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2141                                 return;
2142                         }
2143                 }
2144                 mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2145                 PCWLDBG((CE_NOTE, "pcwl ssid_scan: ssid%d = %s\n", i+1,
2146                     sctbl.wl_srt_ssid));
2147                 PCWLDBG((CE_NOTE, "pcwl ssid_scan: channel = %d\n",
2148                     sctbl.wl_srt_chid));
2149                 PCWLDBG((CE_NOTE, "pcwl ssid_scan: signal level= %d\n",
2150                     sctbl.wl_srt_sl));
2151                 PCWLDBG((CE_NOTE, "pcwl ssid_scan: noise level = %d\n",
2152                     sctbl.wl_srt_anl));
2153                 PCWLDBG((CE_NOTE, "pcwl ssid_scan: bssid%d ="
2154                     " %x %x %x %x %x %x\n\n", i+1,
2155                     sctbl.wl_srt_bssid[0],
2156                     sctbl.wl_srt_bssid[1],
2157                     sctbl.wl_srt_bssid[2],
2158                     sctbl.wl_srt_bssid[3],
2159                     sctbl.wl_srt_bssid[4],
2160                     sctbl.wl_srt_bssid[5]));
2161         }
2162 
2163 }
2164 
2165 /*
2166  * delay in which the mutex is not hold.
2167  * assuming the mutex has already been hold.
2168  */
2169 static void
2170 pcwl_delay(pcwl_maci_t *pcwl_p, clock_t microsecs)
2171 {
2172         ASSERT(mutex_owned(&pcwl_p->pcwl_glock));
2173 
2174         mutex_exit(&pcwl_p->pcwl_glock);
2175         delay(drv_usectohz(microsecs));
2176         mutex_enter(&pcwl_p->pcwl_glock);
2177 }
2178 
2179 static int
2180 pcwl_reset_backend(pcwl_maci_t *pcwl_p)
2181 {
2182         uint16_t ret = 0;
2183 
2184         if (ret =  pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) {
2185                 return ((int)ret);
2186         }
2187 
2188         pcwl_delay(pcwl_p, 100000); /* wait .1 sec */
2189 
2190         if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) {
2191                 return ((int)ret);
2192         }
2193         pcwl_delay(pcwl_p, 100000); /* wait .1 sec */
2194 
2195         PCWL_DISABLE_INTR(pcwl_p);
2196         return (PCWL_SUCCESS);
2197 }
2198 
2199 
2200 /*
2201  * get card capability (WEP, default channel), setup broadcast, mac addresses
2202  */
2203 static int
2204 pcwl_get_cap(pcwl_maci_t *pcwl_p)
2205 {
2206         uint16_t stat, ch_no;
2207         uint16_t buf[ETHERADDRL >> 1];
2208 
2209         bzero(buf, ETHERADDRL);
2210         if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_OWN_CHNL, &ch_no)) {
2211                 cmn_err(CE_CONT, "pcwl get_cap: get def channel failed"
2212                     " %x\n", stat);
2213                 return ((int)stat);
2214         }
2215         if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_WEP_AVAIL,
2216             &pcwl_p->pcwl_has_wep)) {
2217                 cmn_err(CE_CONT, "pcwl get_cap: get WEP capability failed"
2218                     " %x\n", stat);
2219                 return ((int)stat);
2220         }
2221         if (stat = pcwl_get_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf)) {
2222                 cmn_err(CE_CONT, "pcwl get_cap: get macaddr failed"
2223                     " %x\n", stat);
2224                 return ((int)stat);
2225         }
2226 
2227         /*
2228          * don't assume m_xxx members are 16-bit aligned
2229          */
2230         PCWL_SWAP16(buf, ETHERADDRL);
2231         ether_copy(buf, pcwl_p->pcwl_mac_addr);
2232         return (PCWL_SUCCESS);
2233 }
2234 
2235 static int
2236 pcwl_init_nicmem(pcwl_maci_t *pcwl_p)
2237 {
2238         uint16_t ret, i;
2239         uint16_t rc;
2240 
2241         for (i = 0; i < WL_XMT_BUF_NUM; i++) {
2242                 ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &rc);
2243                 if (ret) {
2244                         cmn_err(CE_WARN,
2245                             "pcwl: alloc NIC Tx buf failed %x\n", ret);
2246                         return (PCWL_FAIL);
2247                 }
2248                 pcwl_p->pcwl_txring.wl_tx_fids[i] = rc;
2249                 pcwl_p->pcwl_txring.wl_tx_ring[i] = 0;
2250                 PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem_id[%d]=%x\n", i, rc));
2251         }
2252         pcwl_p->pcwl_txring.wl_tx_prod = pcwl_p->pcwl_txring.wl_tx_cons = 0;
2253 
2254         ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &pcwl_p->pcwl_mgmt_id);
2255         if (ret) {
2256                 cmn_err(CE_WARN, "pcwl: alloc NIC Mgmt buf failed %x\n", ret);
2257                 return (PCWL_FAIL);
2258         }
2259         PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem mgmt_id=%x\n",
2260             pcwl_p->pcwl_mgmt_id));
2261         return (PCWL_SUCCESS);
2262 }
2263 
2264 static int
2265 pcwl_loaddef_rf(pcwl_maci_t *pcwl_p)
2266 {
2267         pcwl_p->pcwl_rf.rf_max_datalen = WL_DEFAULT_DATALEN;
2268         pcwl_p->pcwl_rf.rf_create_ibss = WL_DEFAULT_CREATE_IBSS;
2269         pcwl_p->pcwl_rf.rf_porttype = WL_BSS_BSS;
2270         pcwl_p->pcwl_rf.rf_rts_thresh = WL_DEFAULT_RTS_THRESH;
2271         pcwl_p->pcwl_rf.rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p);
2272         pcwl_p->pcwl_rf.rf_pm_enabled = WL_DEFAULT_PM_ENABLED;
2273         pcwl_p->pcwl_rf.rf_own_chnl = WL_DEFAULT_CHAN;
2274         (void) strcpy(pcwl_p->pcwl_rf.rf_own_ssid, "");
2275         (void) strcpy(pcwl_p->pcwl_rf.rf_desired_ssid, "");
2276         (void) strcpy(pcwl_p->pcwl_rf.rf_nodename, "");
2277         pcwl_p->pcwl_rf.rf_encryption = WL_NOENCRYPTION;
2278         pcwl_p->pcwl_rf.rf_authtype = WL_OPENSYSTEM;
2279         pcwl_p->pcwl_rf.rf_tx_crypt_key = WL_DEFAULT_TX_CRYPT_KEY;
2280         bzero((pcwl_p->pcwl_rf.rf_ckeys), sizeof (rf_ckey_t) * 4);
2281 
2282         pcwl_p->pcwl_rf.rf_promiscuous = 0;
2283 
2284         return (pcwl_config_rf(pcwl_p));
2285 }
2286 
2287 static int
2288 pcwl_config_rf(pcwl_maci_t *pcwl_p)
2289 {
2290         pcwl_rf_t *rf_p = &pcwl_p->pcwl_rf;
2291         uint16_t create_ibss, porttype;
2292 
2293         /*
2294          * Lucent card:
2295          * 0 Join ESS or IBSS; 1 Join ESS or join/create IBSS
2296          * PrismII card:
2297          * 3 Join ESS or IBSS(do not create IBSS);
2298          * 1 Join ESS or join/create IBSS
2299          */
2300         create_ibss = rf_p->rf_create_ibss;
2301         if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
2302                 if (rf_p->rf_create_ibss == 0)
2303                         create_ibss = 3;
2304         }
2305         /*
2306          * Lucent card:
2307          * 1 BSS; 3 pseudo IBSS(only for test,not the 802.11 IBSS)
2308          * so porttype register should always be set to 1
2309          * PrismII card:
2310          * 0 IBSS; 1 BSS; 2 WDS; 3 pseudo IBSS; 6 hostAP
2311          */
2312         switch (pcwl_p->pcwl_chip_type) {
2313         case PCWL_CHIP_PRISMII:
2314                 if (rf_p->rf_porttype == WL_BSS_BSS)
2315                         porttype = 1;
2316                 else if (rf_p->rf_porttype == WL_BSS_IBSS)
2317                         porttype = 0;
2318                 else
2319                         porttype = 0;
2320                 break;
2321         case PCWL_CHIP_LUCENT:
2322         default:
2323                 porttype = 1;
2324         }
2325 
2326 
2327         FIL_LTV(pcwl_p, PCWL_MCBUF_LEN, WL_RID_MCAST, 0);
2328         FIL_LTV(pcwl_p, 2,      WL_RID_PROMISC,         0);
2329         FIL_LTV(pcwl_p, 2,      WL_RID_TICK_TIME,       0);
2330 
2331         FIL_LTV(pcwl_p, 2, WL_RID_MAX_DATALEN, rf_p->rf_max_datalen);
2332         FIL_LTV(pcwl_p, 2, WL_RID_CREATE_IBSS, create_ibss);
2333         FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, porttype);
2334         FIL_LTV(pcwl_p, 2, WL_RID_RTS_THRESH, rf_p->rf_rts_thresh);
2335         FIL_LTV(pcwl_p, 2, WL_RID_TX_RATE, rf_p->rf_tx_rate);
2336         FIL_LTV(pcwl_p, 2, WL_RID_SYSTEM_SCALE, rf_p->rf_system_scale);
2337         FIL_LTV(pcwl_p, 2, WL_RID_PM_ENABLED, rf_p->rf_pm_enabled);
2338         FIL_LTV(pcwl_p, 2, WL_RID_MAX_SLEEP, rf_p->rf_max_sleep);
2339         FIL_LTV(pcwl_p, 2, WL_RID_OWN_CHNL, rf_p->rf_own_chnl);
2340 
2341         PUT_STR(pcwl_p, WL_RID_OWN_SSID, rf_p->rf_own_ssid);
2342         PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, rf_p->rf_desired_ssid);
2343         PUT_STR(pcwl_p, WL_RID_NODENAME, rf_p->rf_nodename);
2344 
2345         if (!pcwl_p->pcwl_has_wep)
2346                 goto done;
2347 
2348         switch (pcwl_p->pcwl_chip_type) {
2349         case PCWL_CHIP_PRISMII: {
2350                 int i;
2351 
2352                 for (i = 0; i < 4; i++) {
2353                         int k_len = strlen((char *)rf_p->rf_ckeys[i].ckey_dat);
2354                         if (k_len == 0)
2355                                 continue;
2356                         k_len = k_len > 5 ? 14 : 6;
2357                         PUT_LTV(pcwl_p, k_len, WL_RID_CRYPT_KEY0_P2 + i,
2358                             (uint16_t *)&rf_p->rf_ckeys[i].ckey_dat);
2359                 }
2360                 FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY_P2,
2361                     rf_p->rf_tx_crypt_key);
2362                 FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_P2,
2363                     rf_p->rf_authtype);
2364                 FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION_P2,
2365                     rf_p->rf_encryption);
2366                 if (pcwl_p->pcwl_rf.rf_promiscuous)
2367                         FIL_LTV(pcwl_p, 2, WL_RID_PROMISC, 1);
2368                 }
2369                 break;
2370         case PCWL_CHIP_LUCENT:
2371         default:
2372                 FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION,
2373                     rf_p->rf_encryption);
2374                 FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_L,
2375                     rf_p->rf_authtype);
2376                 FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY,
2377                     rf_p->rf_tx_crypt_key);
2378                 PUT_LTV(pcwl_p, sizeof (rf_p->rf_ckeys),
2379                     WL_RID_DEFLT_CRYPT_KEYS,
2380                     (uint16_t *)rf_p->rf_ckeys);
2381                 break;
2382         }
2383 done:
2384         return (PCWL_SUCCESS);
2385 }
2386 
2387 static void
2388 pcwl_start_locked(pcwl_maci_t *pcwl_p)
2389 {
2390         pcwl_p->pcwl_flag |= PCWL_CARD_INTREN;
2391         PCWL_ENABLE_INTR(pcwl_p);
2392 }
2393 
2394 static void
2395 pcwl_stop_locked(pcwl_maci_t *pcwl_p)
2396 {
2397         PCWL_DISABLE_INTR(pcwl_p);
2398         pcwl_p->pcwl_flag &= (~PCWL_CARD_INTREN);
2399         PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC|
2400             WL_EV_ALLOC|WL_EV_INFO|WL_EV_INFO_DROP);
2401         PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC|
2402             WL_EV_ALLOC| WL_EV_INFO|WL_EV_INFO_DROP);
2403 }
2404 
2405 /*ARGSUSED*/
2406 static int
2407 pcwl_saddr_locked(pcwl_maci_t *pcwl_p)
2408 {
2409         int ret;
2410         uint16_t buf[ETHERADDRL >> 1];
2411 
2412         ether_copy(pcwl_p->pcwl_mac_addr, buf);
2413         PCWL_SWAP16(buf, ETHERADDRL);
2414         ret = pcwl_put_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf);
2415         if (ret) {
2416                 cmn_err(CE_WARN, "pcwl set_mac_addr: failed %x\n", ret);
2417                 return (PCWL_FAIL);
2418         }
2419         return (PCWL_SUCCESS);
2420 }
2421 
2422 static void
2423 pcwl_chip_type(pcwl_maci_t *pcwl_p)
2424 {
2425         pcwl_ltv_ver_t ver;
2426         pcwl_ltv_fwver_t f;
2427 
2428         bzero(&ver, sizeof (ver));
2429         (void) pcwl_get_ltv(pcwl_p, sizeof (ver),
2430             WL_RID_CARD_ID, (uint16_t *)&ver);
2431         PCWLDBG((CE_NOTE, "card id:%04x-%04x-%04x-%04x\n",
2432             ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor));
2433         if ((ver.wl_compid & 0xf000) != 0x8000)
2434                 return; /* lucent */
2435 
2436         pcwl_p->pcwl_chip_type = PCWL_CHIP_PRISMII;
2437         (void) pcwl_get_ltv(pcwl_p, sizeof (ver), WL_RID_COMP_IDENT,
2438             (uint16_t *)&ver);
2439         PCWLDBG((CE_NOTE, "PRISM-II ver:%04x-%04x-%04x-%04x\n",
2440             ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor));
2441 
2442         bzero(&f, sizeof (f));
2443         (void) pcwl_get_ltv(pcwl_p, sizeof (f), WL_RID_FWVER, (uint16_t *)&f);
2444         PCWL_SWAP16((uint16_t *)&f, sizeof (f));
2445         PCWLDBG((CE_NOTE, "Firmware Pri:%s 2,3:%s\n",
2446             (char *)f.pri, (char *)f.st));
2447 }
2448 
2449 /*
2450  * Brussels support
2451  */
2452 /*
2453  * MAC_PROP_WL_ESSID
2454  */
2455 static int
2456 pcwl_set_essid(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2457 {
2458         char            *value;
2459         pcwl_rf_t       *rf_p;
2460         wl_essid_t      *iw_essid = (wl_essid_t *)wldp_buf;
2461 
2462         rf_p = &pcwl_p->pcwl_rf;
2463 
2464         value = iw_essid->wl_essid_essid;
2465         (void) strncpy(rf_p->rf_desired_ssid, value,
2466             MIN(32, strlen(value)));
2467         rf_p->rf_desired_ssid[strlen(value)] = '\0';
2468         (void) strncpy(rf_p->rf_own_ssid, value,
2469             MIN(32, strlen(value)));
2470         rf_p->rf_own_ssid[strlen(value)] = '\0';
2471 
2472         PCWLDBG((CE_CONT, "pcwl: set: desired essid=%s\n",
2473             rf_p->rf_desired_ssid));
2474 
2475         return (ENETRESET);
2476 
2477 }
2478 
2479 static int
2480 pcwl_get_essid(pcwl_maci_t *pcwl_p, void *wldp_buf)
2481 {
2482         char            ssid[36];
2483         uint16_t        ret;
2484         uint16_t        val;
2485         int             len;
2486         int             err = 0;
2487         wl_essid_t      ow_essid;
2488         pcwl_rf_t       *rf_p;
2489 
2490         rf_p = &pcwl_p->pcwl_rf;
2491         bzero(&ow_essid, sizeof (wl_essid_t));
2492         bzero(ssid, sizeof (ssid));
2493 
2494         ret =  pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
2495         if (ret) {
2496                 err = EIO;
2497                 return (err);
2498         }
2499         PCWLDBG((CE_NOTE, "PortStatus = %d\n", val));
2500 
2501         switch (val) {
2502         case WL_PORT_DISABLED:
2503         case WL_PORT_INITIAL:
2504                 len = mi_strlen(rf_p->rf_desired_ssid);
2505                 ow_essid.wl_essid_length = len;
2506                 bcopy(rf_p->rf_desired_ssid, ow_essid.wl_essid_essid,
2507                     len);
2508                 break;
2509         case WL_PORT_TO_IBSS:
2510         case WL_PORT_TO_BSS:
2511         case WL_PORT_OOR:
2512                 (void) pcwl_get_ltv((pcwl_p), 34, WL_RID_SSID,
2513                     (uint16_t *)ssid);
2514                 PCWL_SWAP16((uint16_t *)(ssid+2), *(uint16_t *)ssid);
2515                 ssid[*(uint16_t *)ssid + 2] = '\0';
2516                 len = mi_strlen(ssid+2);
2517                 ow_essid.wl_essid_length = len;
2518                 bcopy(ssid + 2, ow_essid.wl_essid_essid, len);
2519                 break;
2520         default:
2521                 err = EINVAL;
2522                 break;
2523         }
2524 
2525         bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t));
2526 
2527         return (err);
2528 }
2529 
2530 /*
2531  * MAC_PROP_WL_BSSID
2532  */
2533 static int
2534 pcwl_get_bssid(pcwl_maci_t *pcwl_p, void *wldp_buf)
2535 {
2536         uint16_t        ret;
2537         uint16_t        retval;
2538         uint8_t         bssid[6];
2539         int             err = 0;
2540 
2541         if (ret = pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval)) {
2542                 err = EIO;
2543                 return (err);
2544         }
2545 
2546         PCWLDBG((CE_NOTE, "PortStatus = %d\n", ret));
2547 
2548         if (retval == WL_PORT_DISABLED || retval == WL_PORT_INITIAL) {
2549                 bzero(wldp_buf, sizeof (wl_bssid_t));
2550         } else if (retval == WL_PORT_TO_IBSS ||
2551             retval == WL_PORT_TO_BSS || retval == WL_PORT_OOR) {
2552                 (void) pcwl_get_ltv(pcwl_p, 6,
2553                     WL_RID_BSSID, (uint16_t *)bssid);
2554                 PCWL_SWAP16((uint16_t *)bssid, 6);
2555                 bcopy(bssid, wldp_buf, sizeof (wl_bssid_t));
2556         }
2557 
2558         PCWLDBG((CE_CONT, "pcwl_get_bssid: bssid=%x %x %x %x %x %x\n",
2559             bssid[0], bssid[1], bssid[2],
2560             bssid[3], bssid[4], bssid[5]));
2561 
2562         return (err);
2563 }
2564 
2565 /*
2566  * MAC_PROP_WL_LINKSTATUS
2567  */
2568 static int
2569 pcwl_get_linkstatus(pcwl_maci_t *pcwl_p, void *wldp_buf)
2570 {
2571         uint16_t        ret;
2572         uint16_t        retval;
2573         int             err = 0;
2574 
2575         ret =  pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval);
2576         if (ret) {
2577                 err = EIO;
2578                 PCWLDBG((CE_WARN, "cfg_linkstatus_get_error\n"));
2579                 return (err);
2580         }
2581         PCWLDBG((CE_NOTE, "PortStatus = %d\n", retval));
2582 
2583         switch (retval) {
2584         case WL_PORT_DISABLED:
2585         case WL_PORT_INITIAL:
2586                 *(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED;
2587                 break;
2588         case WL_PORT_TO_IBSS:
2589         case WL_PORT_TO_BSS:
2590         case WL_PORT_OOR:
2591                 *(wl_linkstatus_t *)wldp_buf = WL_CONNECTED;
2592                 break;
2593         default:
2594                 err = EINVAL;
2595                 break;
2596         }
2597 
2598         return (err);
2599 }
2600 
2601 /*
2602  * MAC_PROP_WL_BSSTYP
2603  */
2604 static int
2605 pcwl_set_bsstype(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2606 {
2607         uint16_t        ret;
2608         pcwl_rf_t       *rf_p;
2609         int             err = ENETRESET;
2610 
2611         rf_p = &pcwl_p->pcwl_rf;
2612 
2613         ret = (uint16_t)(*(wl_bss_type_t *)wldp_buf);
2614         if ((ret != WL_BSS_BSS) &&
2615             (ret != WL_BSS_IBSS) &&
2616             (ret != WL_BSS_ANY)) {
2617                 err = ENOTSUP;
2618                 return (err);
2619         }
2620 
2621         rf_p->rf_porttype = ret;
2622 
2623         return (err);
2624 }
2625 
2626 static void
2627 pcwl_get_bsstype(pcwl_maci_t *pcwl_p, void *wldp_buf)
2628 {
2629         pcwl_rf_t *rf_p;
2630 
2631         rf_p = &pcwl_p->pcwl_rf;
2632 
2633         *(wl_bss_type_t *)wldp_buf = rf_p->rf_porttype;
2634 
2635         PCWLDBG((CE_CONT, "pcwl_get_bsstype: porttype=%d\n",
2636             rf_p->rf_porttype));
2637 }
2638 
2639 /*
2640  * MAC_PROP_WL_PHY_CONFIG
2641  */
2642 static int
2643 pcwl_set_phy(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2644 {
2645         uint16_t        ret;
2646         pcwl_rf_t       *rf_p;
2647         int             err = ENETRESET;
2648         wl_phy_conf_t   *phy = (wl_phy_conf_t *)wldp_buf;
2649 
2650         rf_p = &pcwl_p->pcwl_rf;
2651         ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel);
2652         if (ret < 1 || ret > 14) {
2653                 err = ENOTSUP;
2654                 return (err);
2655         }
2656 
2657         rf_p->rf_own_chnl = ret;
2658 
2659         PCWLDBG((CE_CONT, "pcwl: set channel=%d\n", rf_p->rf_own_chnl));
2660 
2661         return (err);
2662 }
2663 
2664 static int
2665 pcwl_get_phy(pcwl_maci_t *pcwl_p, void *wldp_buf)
2666 {
2667         uint16_t        retval;
2668         wl_dsss_t       *dsss = (wl_dsss_t *)wldp_buf;
2669         int             err = 0;
2670 
2671         if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CURRENT_CHNL, &retval)) {
2672                 err = EIO;
2673                 return (err);
2674         }
2675 
2676         dsss->wl_dsss_channel = retval;
2677         PCWLDBG((CE_CONT, "pcwl_get_phy: channel=%d\n", retval));
2678         dsss->wl_dsss_subtype = WL_DSSS;
2679 
2680         return (err);
2681 }
2682 
2683 /*
2684  * MAC_PROP_WL_DESIRED_RATESa
2685  */
2686 static int
2687 pcwl_set_desrates(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2688 {
2689         int             err = ENETRESET;
2690         char            rates[4];
2691         char            maxrate;
2692         uint16_t        i;
2693         pcwl_rf_t       *rf_p;
2694         wl_rates_t      *iw_rates = (wl_rates_t *)wldp_buf;
2695 
2696         rf_p = &pcwl_p->pcwl_rf;
2697 
2698         bzero(rates, sizeof (rates));
2699 
2700         for (i = 0; i < 4; i++) {
2701                 rates[i] = iw_rates->wl_rates_rates[i];
2702                 PCWLDBG((CE_CONT, "pcwl: set tx_rate[%d]=%d\n", i, rates[i]));
2703         }
2704         PCWLDBG((CE_CONT, "pcwl: set rate_num=%d\n", iw_rates->wl_rates_num));
2705 
2706         switch (iw_rates->wl_rates_num) {
2707         case 1:
2708                 switch (rates[0]) {
2709                 case WL_RATE_1M:
2710                         rf_p->rf_tx_rate = WL_TX_RATE_FIX_1M(pcwl_p);
2711                         break;
2712                 case WL_RATE_2M:
2713                         rf_p->rf_tx_rate = WL_TX_RATE_FIX_2M(pcwl_p);
2714                         break;
2715                 case WL_RATE_11M:
2716                         rf_p->rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p);
2717                         break;
2718                 case WL_RATE_5_5M:
2719                         rf_p->rf_tx_rate = WL_TX_RATE_FIX_5M(pcwl_p);
2720                         break;
2721                 default:
2722                         err = EINVAL;
2723                         break;
2724                 }
2725                 break;
2726         case 2:
2727                 maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]);
2728                 switch (maxrate) {
2729                 case WL_RATE_2M:
2730                         rf_p->rf_tx_rate = WL_TX_RATE_AUTO_L(pcwl_p);
2731                         break;
2732                 case WL_RATE_11M:
2733                         rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
2734                         break;
2735                 case WL_RATE_5_5M:
2736                         rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p);
2737                         break;
2738                 default:
2739                         err = EINVAL;
2740                         break;
2741                 }
2742                 break;
2743         case 3:
2744                 maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]);
2745                 maxrate = (rates[2] > maxrate ? rates[2] : maxrate);
2746                 switch (maxrate) {
2747                 case WL_RATE_11M:
2748                         rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
2749                         break;
2750                 case WL_RATE_5_5M:
2751                         rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p);
2752                         break;
2753                 default:
2754                         err = EINVAL;
2755                         break;
2756                 }
2757                 break;
2758         case 4:
2759                 rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
2760                 break;
2761         default:
2762                 err = ENOTSUP;
2763                 break;
2764         }
2765         PCWLDBG((CE_CONT, "pcwl: set tx_rate=%d\n", rf_p->rf_tx_rate));
2766 
2767         return (err);
2768 }
2769 
2770 static int
2771 pcwl_get_desrates(pcwl_maci_t *pcwl_p, void *wldp_buf)
2772 {
2773         uint16_t        rate;
2774         int             err = 0;
2775 
2776         if (pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate)) {
2777                 err = EIO;
2778                 return (err);
2779         }
2780 
2781         if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
2782                 ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2783                 switch (rate) {
2784                 case WL_SPEED_1Mbps_P2:
2785                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2786                             WL_RATE_1M;
2787                         break;
2788                 case WL_SPEED_2Mbps_P2:
2789                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2790                             WL_RATE_2M;
2791                         break;
2792                 case WL_SPEED_55Mbps_P2:
2793                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2794                             WL_RATE_5_5M;
2795                         break;
2796                 case WL_SPEED_11Mbps_P2:
2797                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2798                             WL_RATE_11M;
2799                         break;
2800                 default:
2801                         err = EINVAL;
2802                         break;
2803                 }
2804         } else {
2805                 switch (rate) {
2806                 case WL_L_TX_RATE_FIX_1M:
2807                         ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2808                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2809                             WL_RATE_1M;
2810                         break;
2811                 case WL_L_TX_RATE_FIX_2M:
2812                         ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2813                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2814                             WL_RATE_2M;
2815                         break;
2816                 case WL_L_TX_RATE_AUTO_H:
2817                         ((wl_rates_t *)wldp_buf)->wl_rates_num = 4;
2818                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2819                             WL_RATE_1M;
2820                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
2821                             WL_RATE_2M;
2822                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] =
2823                             WL_RATE_5_5M;
2824                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[3] =
2825                             WL_RATE_11M;
2826                         break;
2827                 case WL_L_TX_RATE_FIX_5M:
2828                         ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2829                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2830                             WL_RATE_5_5M;
2831                         break;
2832                 case WL_L_TX_RATE_FIX_11M:
2833                         ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2834                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2835                             WL_RATE_11M;
2836                         break;
2837                 case WL_L_TX_RATE_AUTO_L:
2838                         ((wl_rates_t *)wldp_buf)->wl_rates_num = 2;
2839                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2840                             WL_RATE_1M;
2841                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
2842                             WL_RATE_2M;
2843                         break;
2844                 case WL_L_TX_RATE_AUTO_M:
2845                         ((wl_rates_t *)wldp_buf)->wl_rates_num = 3;
2846                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2847                             WL_RATE_1M;
2848                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
2849                             WL_RATE_2M;
2850                         (((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] =
2851                             WL_RATE_5_5M;
2852                         break;
2853                 default:
2854                         err = EINVAL;
2855                         break;
2856                 }
2857         }
2858         PCWLDBG((CE_CONT, "pcwl: get rate=%d\n", rate));
2859 
2860         return (err);
2861 }
2862 
2863 /*
2864  * MAC_PROP_WL_SUP_RATE
2865  */
2866 static void
2867 pcwl_get_suprates(void *wldp_buf)
2868 {
2869         wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf;
2870 
2871         wl_rates->wl_rates_num = 4;
2872         wl_rates->wl_rates_rates[0] = WL_RATE_1M;
2873         wl_rates->wl_rates_rates[1] = WL_RATE_2M;
2874         wl_rates->wl_rates_rates[2] = WL_RATE_5_5M;
2875         wl_rates->wl_rates_rates[3] = WL_RATE_11M;
2876 }
2877 
2878 /*
2879  * MAC_PROP_WL_POWER_MODE
2880  */
2881 static int
2882 pcwl_set_powermode(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2883 {
2884         uint16_t        ret;
2885         pcwl_rf_t       *rf_p;
2886         int             err = 0;
2887 
2888         rf_p = &pcwl_p->pcwl_rf;
2889 
2890         ret = (uint16_t)(((wl_ps_mode_t *)wldp_buf)->wl_ps_mode);
2891         if (ret != WL_PM_AM && ret != WL_PM_MPS && ret != WL_PM_FAST) {
2892                 err = ENOTSUP;
2893                 return (err);
2894         }
2895 
2896         rf_p->rf_pm_enabled = ret;
2897 
2898         return (err);
2899 
2900 }
2901 
2902 static void
2903 pcwl_get_powermode(pcwl_maci_t *pcwl_p, void *wldp_buf)
2904 {
2905         pcwl_rf_t *rf_p;
2906 
2907         rf_p = &pcwl_p->pcwl_rf;
2908         ((wl_ps_mode_t *)wldp_buf)->wl_ps_mode = rf_p->rf_pm_enabled;
2909 }
2910 
2911 /*
2912  * MAC_PROP_AUTH_MODE
2913  */
2914 static int
2915 pcwl_set_authmode(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2916 {
2917         uint16_t        ret;
2918         pcwl_rf_t       *rf_p;
2919         int             err = ENETRESET;
2920 
2921         rf_p = &pcwl_p->pcwl_rf;
2922 
2923         ret = (uint16_t)(*(wl_authmode_t *)wldp_buf);
2924         if (ret != WL_OPENSYSTEM && ret != WL_SHAREDKEY) {
2925                 err = ENOTSUP;
2926                 return (err);
2927         }
2928 
2929         rf_p->rf_authtype = ret;
2930 
2931         return (err);
2932 }
2933 
2934 static void
2935 pcwl_get_authmode(pcwl_maci_t *pcwl_p, void *wldp_buf)
2936 {
2937         pcwl_rf_t       *rf_p;
2938 
2939         rf_p = &pcwl_p->pcwl_rf;
2940         *(wl_authmode_t *)wldp_buf = rf_p->rf_authtype;
2941 }
2942 
2943 /*
2944  * MAC_PROP_WL_ENCRYPTION
2945  */
2946 static int
2947 pcwl_set_encrypt(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2948 {
2949         uint16_t        ret;
2950         pcwl_rf_t       *rf_p;
2951         int             err = ENETRESET;
2952 
2953         rf_p = &pcwl_p->pcwl_rf;
2954 
2955         ret = (uint16_t)(*(wl_encryption_t *)wldp_buf);
2956         PCWLDBG((CE_NOTE, "pcwl_set_encrypt: %d\n", ret));
2957         if (ret != WL_NOENCRYPTION && ret != WL_ENC_WEP) {
2958                 err = ENOTSUP;
2959                 return (err);
2960         }
2961 
2962         rf_p->rf_encryption = ret;
2963 
2964         return (err);
2965 }
2966 
2967 static void
2968 pcwl_get_encrypt(pcwl_maci_t *pcwl_p, void *wldp_buf)
2969 {
2970         pcwl_rf_t *rf_p;
2971 
2972         rf_p = &pcwl_p->pcwl_rf;
2973         *(wl_encryption_t *)wldp_buf = rf_p->rf_encryption;
2974 }
2975 
2976 /*
2977  * MAC_PROP_WL_CREATE_IBSS
2978  */
2979 static int
2980 pcwl_set_ibss(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2981 {
2982         uint16_t        ret;
2983         pcwl_rf_t       *rf_p;
2984         int             err = ENETRESET;
2985 
2986         rf_p = &pcwl_p->pcwl_rf;
2987 
2988         ret = (uint16_t)(*(wl_create_ibss_t *)wldp_buf);
2989         if (ret != 0 && ret != 1) {
2990                 err = ENOTSUP;
2991                 return (err);
2992         }
2993 
2994         rf_p->rf_create_ibss = ret;
2995 
2996         return (err);
2997 }
2998 
2999 static void
3000 pcwl_get_ibss(pcwl_maci_t *pcwl_p, void *wldp_buf)
3001 {
3002         pcwl_rf_t       *rf_p;
3003 
3004         rf_p = &pcwl_p->pcwl_rf;
3005         *(wl_create_ibss_t *)wldp_buf = rf_p->rf_create_ibss;
3006 }
3007 
3008 /*
3009  * MAC_PROP_WL_RSSI
3010  */
3011 static void
3012 pcwl_get_param_rssi(pcwl_maci_t *pcwl_p, void *wldp_buf)
3013 {
3014 
3015         if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
3016                 *(wl_rssi_t *)wldp_buf =
3017                     min((pcwl_p->pcwl_rssi * 15 / 85 + 1), 15);
3018         } else {
3019                 /*
3020                  * According to the description of the
3021                  * datasheet(Lucent card), the signal level
3022                  * value is between 27 -- 154.
3023                  * we reflect these value to 1-15 as rssi.
3024                  */
3025                 if (pcwl_p->pcwl_rssi <= 27)
3026                         *(wl_rssi_t *)wldp_buf = 1;
3027                 else if (pcwl_p->pcwl_rssi > 154)
3028                         *(wl_rssi_t *)wldp_buf = 15;
3029                 else
3030                         *(wl_rssi_t *)wldp_buf =
3031                             min(15, ((pcwl_p->pcwl_rssi - 27) * 15 / 127));
3032         }
3033 }
3034 
3035 /*
3036  * MAC_PROP_WL_KEY_TAB
3037  */
3038 static int
3039 pcwl_set_wepkey(pcwl_maci_t *pcwl_p, const void *wldp_buf)
3040 {
3041         uint16_t        i;
3042         pcwl_rf_t       *rf_p;
3043         wl_wep_key_t    *p_wepkey_tab;
3044 
3045         rf_p = &pcwl_p->pcwl_rf;
3046         bzero((rf_p->rf_ckeys), sizeof (rf_ckey_t) * MAX_NWEPKEYS);
3047 
3048         p_wepkey_tab = (wl_wep_key_t *)wldp_buf;
3049         for (i = 0; i < MAX_NWEPKEYS; i++) {
3050                 if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) {
3051                         rf_p->rf_ckeys[i].ckey_len =
3052                             p_wepkey_tab[i].wl_wep_length;
3053                         bcopy(p_wepkey_tab[i].wl_wep_key,
3054                             rf_p->rf_ckeys[i].ckey_dat,
3055                             p_wepkey_tab[i].wl_wep_length);
3056                         PCWL_SWAP16((uint16_t *)
3057                             &rf_p->rf_ckeys[i].ckey_dat,
3058                             rf_p->rf_ckeys[i].ckey_len + 1);
3059                         PCWLDBG((CE_CONT, "%s, %d\n",
3060                             rf_p->rf_ckeys[i].ckey_dat, i));
3061                 }
3062                 PCWLDBG((CE_CONT, "pcwl: rf_ckeys[%d]=%s\n", i,
3063                     (char *)(rf_p->rf_ckeys[i].ckey_dat)));
3064         }
3065 
3066         return (ENETRESET);
3067 }
3068 
3069 /*
3070  * MAC_PROP_WL_RADIO
3071  */
3072 static void
3073 pcwl_get_radio(void *wldp_buf)
3074 {
3075         wl_radio_t *radio = (wl_radio_t *)wldp_buf;
3076 
3077         *radio = B_TRUE;
3078 }
3079 
3080 /*
3081  * MAC_PROP_WL_ESSLIST
3082  */
3083 static void
3084 pcwl_get_esslist(pcwl_maci_t *pcwl_p, void *wldp_buf)
3085 {
3086         uint16_t        i;
3087         wl_ess_conf_t   *p_ess_conf;
3088         wl_scan_list_t  *scan_item;
3089 
3090         mutex_enter(&pcwl_p->pcwl_scanlist_lock);
3091 
3092         ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
3093             pcwl_p->pcwl_scan_num;
3094 
3095         scan_item = list_head(&pcwl_p->pcwl_scan_list);
3096 
3097         for (i = 0; i < pcwl_p->pcwl_scan_num; i++) {
3098                 if (!scan_item)
3099                         break;
3100 
3101                 p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
3102                     offsetof(wl_ess_list_t, wl_ess_list_ess) +
3103                     i * sizeof (wl_ess_conf_t));
3104                 bcopy(scan_item->wl_val.wl_srt_ssid,
3105                     p_ess_conf->wl_ess_conf_essid.wl_essid_essid,
3106                     mi_strlen(scan_item->wl_val.wl_srt_ssid));
3107                 bcopy(scan_item->wl_val.wl_srt_bssid,
3108                     p_ess_conf->wl_ess_conf_bssid, 6);
3109                 (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype
3110                     = WL_DSSS;
3111                 p_ess_conf->wl_ess_conf_wepenabled =
3112                     (scan_item->wl_val.wl_srt_cap & 0x10 ?
3113                     WL_ENC_WEP : WL_NOENCRYPTION);
3114                 p_ess_conf->wl_ess_conf_bsstype =
3115                     (scan_item->wl_val.wl_srt_cap & 0x1 ?
3116                     WL_BSS_BSS : WL_BSS_IBSS);
3117                 p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel =
3118                     scan_item->wl_val.wl_srt_chid;
3119                 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
3120                         p_ess_conf->wl_ess_conf_sl =
3121                             min(scan_item->wl_val.wl_srt_sl * 15 / 85 + 1,
3122                             15);
3123                 } else {
3124                         if (scan_item->wl_val.wl_srt_sl <= 27)
3125                                 p_ess_conf->wl_ess_conf_sl = 1;
3126                         else if (scan_item->wl_val.wl_srt_sl > 154)
3127                                 p_ess_conf->wl_ess_conf_sl = 15;
3128                         else
3129                                 p_ess_conf->wl_ess_conf_sl = min(15,
3130                                     ((scan_item->wl_val.wl_srt_sl - 27)
3131                                     * 15 / 127));
3132                 }
3133 
3134                 p_ess_conf->wl_supported_rates[0] = WL_RATE_1M;
3135                 p_ess_conf->wl_supported_rates[0] = WL_RATE_2M;
3136                 p_ess_conf->wl_supported_rates[0] = WL_RATE_5_5M;
3137                 p_ess_conf->wl_supported_rates[0] = WL_RATE_11M;
3138 
3139                 scan_item = list_next(&pcwl_p->pcwl_scan_list, scan_item);
3140         }
3141 
3142         mutex_exit(&pcwl_p->pcwl_scanlist_lock);
3143 }
3144 
3145 
3146 /*
3147  * for wificonfig and dladm ioctl
3148  */
3149 
3150 static int
3151 pcwl_cfg_essid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3152 {
3153         char            ssid[36];
3154         uint16_t        i;
3155         uint16_t        val;
3156         pcwl_rf_t       *rf_p;
3157         wldp_t          *infp;
3158         wldp_t          *outfp;
3159         char            *buf;
3160         int             iret;
3161         int             err = 0;
3162 
3163         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3164         if (buf == NULL) {
3165                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3166                     MAX_BUF_LEN));
3167                 return (ENOMEM);
3168         }
3169         outfp = (wldp_t *)buf;
3170         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3171         infp = (wldp_t *)mp->b_rptr;
3172         rf_p = &pcwl_p->pcwl_rf;
3173 
3174 
3175         bzero(ssid, sizeof (ssid));
3176         if (cmd == WLAN_GET_PARAM) {
3177                 err = pcwl_get_essid(pcwl_p, outfp->wldp_buf);
3178                 if (err == EIO) {
3179                         outfp->wldp_length = WIFI_BUF_OFFSET;
3180                         outfp->wldp_result = WL_HW_ERROR;
3181                         goto done;
3182                 }
3183                 (void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
3184                 if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) {
3185                         outfp->wldp_length = WIFI_BUF_OFFSET +
3186                             offsetof(wl_essid_t, wl_essid_essid) +
3187                             mi_strlen(rf_p->rf_desired_ssid);
3188                 } else if (val == WL_PORT_TO_IBSS ||
3189                     val == WL_PORT_TO_BSS ||
3190                     val == WL_PORT_OOR) {
3191                         outfp->wldp_length = WIFI_BUF_OFFSET +
3192                             offsetof(wl_essid_t, wl_essid_essid) +
3193                             mi_strlen(ssid+2);
3194                 } else {
3195                         outfp->wldp_length = WIFI_BUF_OFFSET;
3196                 }
3197                 outfp->wldp_result = WL_SUCCESS;
3198                 PCWLDBG((CE_CONT, "outfp->length=%d\n", outfp->wldp_length));
3199                 PCWLDBG((CE_CONT, "pcwl: get desired essid=%s\n",
3200                     rf_p->rf_desired_ssid));
3201         } else if (cmd == WLAN_SET_PARAM) {
3202                 (void) pcwl_set_essid(pcwl_p, infp->wldp_buf);
3203                 outfp->wldp_length = WIFI_BUF_OFFSET;
3204                 outfp->wldp_result = WL_SUCCESS;
3205         } else {
3206                 kmem_free(buf, MAX_BUF_LEN);
3207                 return (EINVAL);
3208         }
3209 done:
3210         for (i = 0; i < (outfp->wldp_length); i++)
3211                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3212         iret = (int)(outfp->wldp_result);
3213         kmem_free(buf, MAX_BUF_LEN);
3214         return (iret);
3215 }
3216 
3217 static int
3218 pcwl_cfg_bssid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3219 {
3220         uint16_t        i;
3221         int             iret;
3222         wldp_t          *outfp;
3223         char            *buf;
3224         int             err = 0;
3225 
3226         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3227         if (buf == NULL) {
3228                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3229                     MAX_BUF_LEN));
3230                 return (ENOMEM);
3231         }
3232         outfp = (wldp_t *)buf;
3233         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3234 
3235         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t);
3236         if (cmd == WLAN_GET_PARAM) {
3237                 err = pcwl_get_bssid(pcwl_p, outfp->wldp_buf);
3238                 if (err == EIO) {
3239                         outfp->wldp_length = WIFI_BUF_OFFSET;
3240                         outfp->wldp_result = WL_HW_ERROR;
3241                         goto done;
3242                 }
3243                 outfp->wldp_result = WL_SUCCESS;
3244         } else if (cmd == WLAN_SET_PARAM) {
3245                 outfp->wldp_result = WL_READONLY;
3246         } else {
3247                 kmem_free(buf, MAX_BUF_LEN);
3248                 return (EINVAL);
3249         }
3250 done:
3251         for (i = 0; i < (outfp->wldp_length); i++)
3252                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3253         iret = (int)(outfp->wldp_result);
3254         kmem_free(buf, MAX_BUF_LEN);
3255         return (iret);
3256 }
3257 
3258 /*ARGSUSED*/
3259 static int
3260 pcwl_cmd_scan(pcwl_maci_t *pcwl_p)
3261 {
3262         uint16_t vall[18], ret = WL_SUCCESS;
3263         pcwl_rf_t *rf_p;
3264         uint32_t enable, i;
3265         size_t  len;
3266 
3267         rf_p = &pcwl_p->pcwl_rf;
3268 
3269         /*
3270          * The logic of this funtion is really tricky.
3271          * Firstly, the chip can only scan in BSS mode, so necessary
3272          * backup and restore is required before and after the scan
3273          * command.
3274          * Secondly, for Lucent chip, Alrealy associated with an AP
3275          * can only scan the APes on the fixed channel, so we must
3276          * set the desired_ssid as "" before scan and restore after.
3277          * Thirdly, scan cmd is effective only when the card is enabled
3278          * and any 'set' operation(such as set bsstype, ssid)must disable
3279          * the card first and then enable the card after the 'set'
3280          */
3281         enable = pcwl_p->pcwl_flag & PCWL_ENABLED;
3282         len = strlen(rf_p->rf_desired_ssid);
3283 
3284         if (pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) {
3285                 if ((enable) &&
3286                     (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
3287                         ret = (int)WL_HW_ERROR;
3288                         goto done;
3289                 }
3290                 FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, WL_BSS_BSS);
3291         }
3292 
3293         if ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0)) {
3294                 if ((enable) &&
3295                     (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
3296                         ret = (int)WL_HW_ERROR;
3297                         goto done;
3298                 }
3299                 PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, "");
3300         }
3301 
3302         if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
3303                 ret = (int)WL_HW_ERROR;
3304                 goto done;
3305         }
3306         pcwl_delay(pcwl_p, 1000000);
3307 
3308         switch (pcwl_p->pcwl_chip_type) {
3309         case PCWL_CHIP_PRISMII:
3310                 bzero(vall, sizeof (vall));
3311                 vall[0] = 0x3fff; /* channel mask */
3312                 vall[1] = 0x1; /* tx rate */
3313                 for (i = 0; i < WL_MAX_SCAN_TIMES; i++) {
3314                         PUT_LTV(pcwl_p, sizeof (vall),
3315                             WL_RID_HSCAN_REQUEST, vall);
3316                         pcwl_delay(pcwl_p, 1000000);
3317                         if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD)
3318                                 break;
3319                 }
3320                 PCWLDBG((CE_NOTE, "PRISM chip\n"));
3321                 break;
3322 
3323         case PCWL_CHIP_LUCENT:
3324                 PCWLDBG((CE_NOTE, "LUCENT chip\n"));
3325         default:
3326                 for (i = 0; i < WL_MAX_SCAN_TIMES; i++) {
3327                         if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INQUIRE,
3328                             WL_INFO_SCAN_RESULTS)) {
3329                                 ret = (int)WL_HW_ERROR;
3330                                 goto done;
3331                         }
3332                         pcwl_delay(pcwl_p, 500000);
3333                         if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD)
3334                                 break;
3335                 }
3336                 break;
3337         }
3338         if ((pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) ||
3339             ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0))) {
3340                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
3341                         ret = (int)WL_HW_ERROR;
3342                         goto done;
3343                 }
3344                 if (ret = pcwl_config_rf(pcwl_p)) {
3345                         ret = (int)WL_HW_ERROR;
3346                         goto done;
3347                 }
3348                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
3349                         ret = (int)WL_HW_ERROR;
3350                         goto done;
3351                 }
3352 
3353                 pcwl_delay(pcwl_p, 1000000);
3354         }
3355 
3356         if ((!enable) && (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
3357                 ret = (int)WL_HW_ERROR;
3358         }
3359 done:
3360         if (ret)
3361                 cmn_err(CE_WARN, "pcwl: scan failed due to hardware error");
3362         return (ret);
3363 
3364 }
3365 
3366 /*ARGSUSED*/
3367 static int
3368 pcwl_cfg_scan(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3369 {
3370         wldp_t          *outfp;
3371         char            *buf;
3372         uint16_t        i;
3373 
3374         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3375         if (buf == NULL) {
3376                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3377                     MAX_BUF_LEN));
3378                 return (ENOMEM);
3379         }
3380         outfp = (wldp_t *)buf;
3381         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3382 
3383         pcwl_get_esslist(pcwl_p, outfp->wldp_buf);
3384 
3385         outfp->wldp_length = WIFI_BUF_OFFSET +
3386             offsetof(wl_ess_list_t, wl_ess_list_ess) +
3387             pcwl_p->pcwl_scan_num * sizeof (wl_ess_conf_t);
3388         outfp->wldp_result = WL_SUCCESS;
3389 
3390         for (i = 0; i < (outfp->wldp_length); i++)
3391                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3392         kmem_free(buf, MAX_BUF_LEN);
3393         return (WL_SUCCESS);
3394 
3395 }
3396 
3397 /*ARGSUSED*/
3398 static int
3399 pcwl_cfg_linkstatus(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3400 {
3401         wldp_t          *outfp;
3402         char            *buf;
3403         uint16_t        i, val;
3404         int             iret;
3405         int             err = 0;
3406 
3407         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3408         if (buf == NULL) {
3409                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3410                     MAX_BUF_LEN));
3411                 return (ENOMEM);
3412         }
3413         outfp = (wldp_t *)buf;
3414         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3415 
3416         err = pcwl_get_linkstatus(pcwl_p, outfp->wldp_buf);
3417         if (err == EIO) {
3418                 outfp->wldp_length = WIFI_BUF_OFFSET;
3419                 outfp->wldp_result = WL_HW_ERROR;
3420                 goto done;
3421         }
3422 
3423         (void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
3424         if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) {
3425                 outfp->wldp_length = WIFI_BUF_OFFSET +
3426                     sizeof (wl_linkstatus_t);
3427         } else if (val == WL_PORT_TO_IBSS ||
3428             val == WL_PORT_TO_BSS ||
3429             val == WL_PORT_OOR) {
3430                 outfp->wldp_length = WIFI_BUF_OFFSET +
3431                     sizeof (wl_linkstatus_t);
3432         } else {
3433                 outfp->wldp_length = WIFI_BUF_OFFSET;
3434         }
3435 
3436         outfp->wldp_result = WL_SUCCESS;
3437 done:
3438         for (i = 0; i < (outfp->wldp_length); i++)
3439                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3440         iret = (int)(outfp->wldp_result);
3441         kmem_free(buf, MAX_BUF_LEN);
3442         return (iret);
3443 }
3444 
3445 static int
3446 pcwl_cfg_bsstype(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3447 {
3448         uint16_t        i;
3449         wldp_t          *infp;
3450         wldp_t          *outfp;
3451         char            *buf;
3452         int             iret;
3453         int             err = 0;
3454 
3455         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3456         if (buf == NULL) {
3457                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3458                     MAX_BUF_LEN));
3459                 return (ENOMEM);
3460         }
3461         outfp = (wldp_t *)buf;
3462         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3463         infp = (wldp_t *)mp->b_rptr;
3464 
3465         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t);
3466         if (cmd == WLAN_GET_PARAM) {
3467                 pcwl_get_bsstype(pcwl_p, outfp->wldp_buf);
3468                 outfp->wldp_result = WL_SUCCESS;
3469         } else if (cmd == WLAN_SET_PARAM) {
3470                 err = pcwl_set_bsstype(pcwl_p, infp->wldp_buf);
3471                 if (err == ENOTSUP) {
3472                         outfp->wldp_length = WIFI_BUF_OFFSET;
3473                         outfp->wldp_result = WL_NOTSUPPORTED;
3474                         goto done;
3475                 }
3476                 outfp->wldp_result = WL_SUCCESS;
3477         } else {
3478                 kmem_free(buf, MAX_BUF_LEN);
3479                 return (EINVAL);
3480         }
3481 done:
3482         for (i = 0; i < (outfp->wldp_length); i++)
3483                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3484         iret = (int)(outfp->wldp_result);
3485         kmem_free(buf, MAX_BUF_LEN);
3486         return (iret);
3487 }
3488 
3489 static int
3490 pcwl_cfg_phy(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3491 {
3492         uint16_t        i;
3493         wldp_t          *infp;
3494         wldp_t          *outfp;
3495         char            *buf;
3496         int             iret;
3497         int             err = 0;
3498 
3499         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3500         if (buf == NULL) {
3501                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3502                     MAX_BUF_LEN));
3503                 return (ENOMEM);
3504         }
3505         outfp = (wldp_t *)buf;
3506         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3507         infp = (wldp_t *)mp->b_rptr;
3508 
3509         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t);
3510         if (cmd == WLAN_GET_PARAM) {
3511                 err = pcwl_get_phy(pcwl_p, outfp->wldp_buf);
3512                 if (err == EIO) {
3513                         outfp->wldp_length = WIFI_BUF_OFFSET;
3514                         outfp->wldp_result = WL_HW_ERROR;
3515                         goto done;
3516                 }
3517                 outfp->wldp_result = WL_SUCCESS;
3518         } else if (cmd == WLAN_SET_PARAM) {
3519                 err = pcwl_set_phy(pcwl_p, infp->wldp_buf);
3520                 if (err == ENOTSUP) {
3521                         outfp->wldp_length = WIFI_BUF_OFFSET;
3522                         outfp->wldp_result = WL_NOTSUPPORTED;
3523                         goto done;
3524                 }
3525                 outfp->wldp_result = WL_SUCCESS;
3526         } else {
3527                 kmem_free(buf, MAX_BUF_LEN);
3528                 return (EINVAL);
3529         }
3530 done:
3531         for (i = 0; i < (outfp->wldp_length); i++)
3532                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3533         iret = (int)(outfp->wldp_result);
3534         kmem_free(buf, MAX_BUF_LEN);
3535         return (iret);
3536 
3537 }
3538 
3539 static int
3540 pcwl_cfg_desiredrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3541 {
3542         uint16_t        rate;
3543         uint16_t        i;
3544         wldp_t          *infp;
3545         wldp_t          *outfp;
3546         char            *buf;
3547         int             iret;
3548         int             err = 0;
3549 
3550         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3551         if (buf == NULL) {
3552                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3553                     MAX_BUF_LEN));
3554                 return (ENOMEM);
3555         }
3556         outfp = (wldp_t *)buf;
3557         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3558         infp = (wldp_t *)mp->b_rptr;
3559 
3560         if (cmd == WLAN_GET_PARAM) {
3561                 err = pcwl_get_desrates(pcwl_p, outfp->wldp_buf);
3562                 if (err == EIO || err == EINVAL) {
3563                         outfp->wldp_length = WIFI_BUF_OFFSET;
3564                         outfp->wldp_result = WL_NOTSUPPORTED;
3565                         goto done;
3566                 }
3567                 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
3568                         outfp->wldp_length = WIFI_BUF_OFFSET +
3569                             offsetof(wl_rates_t, wl_rates_rates) +
3570                             1 * sizeof (char);
3571                 } else {
3572                         (void) pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate);
3573                         switch (rate) {
3574                         case WL_L_TX_RATE_FIX_1M:
3575                                 outfp->wldp_length = WIFI_BUF_OFFSET +
3576                                     offsetof(wl_rates_t, wl_rates_rates) +
3577                                     1 * sizeof (char);
3578                                 break;
3579                         case WL_L_TX_RATE_FIX_2M:
3580                                 outfp->wldp_length = WIFI_BUF_OFFSET +
3581                                     offsetof(wl_rates_t, wl_rates_rates) +
3582                                     1 * sizeof (char);
3583                                 break;
3584                         case WL_L_TX_RATE_AUTO_H:
3585                                 outfp->wldp_length = WIFI_BUF_OFFSET +
3586                                     offsetof(wl_rates_t, wl_rates_rates) +
3587                                     4 * sizeof (char);
3588                                 break;
3589                         case WL_L_TX_RATE_FIX_5M:
3590                                 outfp->wldp_length = WIFI_BUF_OFFSET +
3591                                     offsetof(wl_rates_t, wl_rates_rates) +
3592                                     1 * sizeof (char);
3593                                 break;
3594                         case WL_L_TX_RATE_FIX_11M:
3595                                 outfp->wldp_length = WIFI_BUF_OFFSET +
3596                                     offsetof(wl_rates_t, wl_rates_rates) +
3597                                     1 * sizeof (char);
3598                                 break;
3599                         case WL_L_TX_RATE_AUTO_L:
3600                                 outfp->wldp_length = WIFI_BUF_OFFSET +
3601                                     offsetof(wl_rates_t, wl_rates_rates) +
3602                                     2 * sizeof (char);
3603                                 break;
3604                         case WL_L_TX_RATE_AUTO_M:
3605                                 outfp->wldp_length = WIFI_BUF_OFFSET +
3606                                     offsetof(wl_rates_t, wl_rates_rates) +
3607                                     3 * sizeof (char);
3608                                 break;
3609                         default:
3610                                 break;
3611                         }
3612                 }
3613                 outfp->wldp_result = WL_SUCCESS;
3614         } else if (cmd == WLAN_SET_PARAM) {
3615                 err = pcwl_set_desrates(pcwl_p, infp->wldp_buf);
3616                 if (err == EINVAL) {
3617                         outfp->wldp_length = WIFI_BUF_OFFSET;
3618                         outfp->wldp_result = WL_NOTSUPPORTED;
3619                         goto done;
3620                 }
3621                 if (err == ENOTSUP) {
3622                         outfp->wldp_length = WIFI_BUF_OFFSET;
3623                         outfp->wldp_result = WL_LACK_FEATURE;
3624                         goto done;
3625                 }
3626 
3627                 outfp->wldp_length = WIFI_BUF_OFFSET;
3628                 outfp->wldp_result = WL_SUCCESS;
3629         } else {
3630                 kmem_free(buf, MAX_BUF_LEN);
3631                 return (EINVAL);
3632         }
3633 done:
3634         for (i = 0; i < (outfp->wldp_length); i++)
3635                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3636         iret = (int)(outfp->wldp_result);
3637         kmem_free(buf, MAX_BUF_LEN);
3638         return (iret);
3639 }
3640 
3641 /*ARGSUSED*/
3642 static int
3643 pcwl_cfg_supportrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3644 {
3645         uint16_t i;
3646         wldp_t *outfp;
3647         char *buf;
3648 
3649         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3650         if (buf == NULL) {
3651                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3652                     MAX_BUF_LEN));
3653                 return (ENOMEM);
3654         }
3655         outfp = (wldp_t *)buf;
3656         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3657 
3658         if (cmd == WLAN_GET_PARAM) {
3659                 pcwl_get_suprates(outfp->wldp_buf);
3660                 outfp->wldp_length = WIFI_BUF_OFFSET +
3661                     offsetof(wl_rates_t, wl_rates_rates) +
3662                     4 * sizeof (char);
3663                 outfp->wldp_result = WL_SUCCESS;
3664                 for (i = 0; i < (outfp->wldp_length); i++)
3665                         (void) mi_mpprintf_putc((char *)mp, buf[i]);
3666                 kmem_free(buf, MAX_BUF_LEN);
3667                 return (WL_SUCCESS);
3668         } else {
3669                 kmem_free(buf, MAX_BUF_LEN);
3670                 return (EINVAL);
3671         }
3672 }
3673 
3674 static int
3675 pcwl_cfg_powermode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3676 {
3677         uint16_t        i;
3678         wldp_t          *infp;
3679         wldp_t          *outfp;
3680         char            *buf;
3681         int             iret;
3682         int             err = 0;
3683 
3684         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3685         if (buf == NULL) {
3686                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3687                     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_ps_mode_t);
3695         if (cmd == WLAN_GET_PARAM) {
3696                 pcwl_get_powermode(pcwl_p, outfp->wldp_buf);
3697                 outfp->wldp_result = WL_SUCCESS;
3698         } else if (cmd == WLAN_SET_PARAM) {
3699                 err = pcwl_set_powermode(pcwl_p, infp->wldp_buf);
3700                 if (err == ENOTSUP) {
3701                         outfp->wldp_length = WIFI_BUF_OFFSET;
3702                         outfp->wldp_result = WL_NOTSUPPORTED;
3703                         goto done;
3704                 }
3705                 outfp->wldp_result = WL_SUCCESS;
3706         } else {
3707                 kmem_free(buf, MAX_BUF_LEN);
3708                 return (EINVAL);
3709         }
3710 done:
3711         for (i = 0; i < (outfp->wldp_length); i++)
3712                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3713         iret = (int)(outfp->wldp_result);
3714         kmem_free(buf, MAX_BUF_LEN);
3715         return (iret);
3716 
3717 }
3718 
3719 static int
3720 pcwl_cfg_authmode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3721 {
3722         uint16_t        i;
3723         wldp_t          *infp;
3724         wldp_t          *outfp;
3725         char            *buf;
3726         int             iret;
3727         int             err = 0;
3728 
3729         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3730         if (buf == NULL) {
3731                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3732                     MAX_BUF_LEN));
3733                 return (ENOMEM);
3734         }
3735         outfp = (wldp_t *)buf;
3736         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3737         infp = (wldp_t *)mp->b_rptr;
3738 
3739         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_authmode_t);
3740         if (cmd == WLAN_GET_PARAM) {
3741                 pcwl_get_authmode(pcwl_p, outfp->wldp_buf);
3742                 outfp->wldp_result = WL_SUCCESS;
3743         } else if (cmd == WLAN_SET_PARAM) {
3744                 err = pcwl_set_authmode(pcwl_p, infp->wldp_buf);
3745                 if (err == ENOTSUP) {
3746                         outfp->wldp_length = WIFI_BUF_OFFSET;
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 done:
3756         for (i = 0; i < (outfp->wldp_length); i++)
3757                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3758         iret = (int)(outfp->wldp_result);
3759         kmem_free(buf, MAX_BUF_LEN);
3760         return (iret);
3761 }
3762 
3763 static int
3764 pcwl_cfg_encryption(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3765 {
3766         uint16_t        i;
3767         wldp_t          *infp;
3768         wldp_t          *outfp;
3769         char            *buf;
3770         int             iret;
3771         int             err = 0;
3772 
3773         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3774         if (buf == NULL) {
3775                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3776                     MAX_BUF_LEN));
3777                 return (ENOMEM);
3778         }
3779         outfp = (wldp_t *)buf;
3780         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3781         infp = (wldp_t *)mp->b_rptr;
3782 
3783         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
3784         if (cmd == WLAN_GET_PARAM) {
3785                 pcwl_get_encrypt(pcwl_p, outfp->wldp_buf);
3786                 outfp->wldp_result = WL_SUCCESS;
3787         } else if (cmd == WLAN_SET_PARAM) {
3788                 err = pcwl_set_encrypt(pcwl_p, infp->wldp_buf);
3789                 if (err == ENOTSUP) {
3790                         outfp->wldp_length = WIFI_BUF_OFFSET;
3791                         outfp->wldp_result = WL_NOTSUPPORTED;
3792                         goto done;
3793                 }
3794                 outfp->wldp_result = WL_SUCCESS;
3795         } else {
3796                 kmem_free(buf, MAX_BUF_LEN);
3797                 return (EINVAL);
3798         }
3799 done:
3800         for (i = 0; i < (outfp->wldp_length); i++)
3801                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3802         iret = (int)(outfp->wldp_result);
3803         kmem_free(buf, MAX_BUF_LEN);
3804         return (iret);
3805 }
3806 
3807 static int
3808 pcwl_cfg_wepkeyid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3809 {
3810         uint16_t i, ret;
3811         pcwl_rf_t *rf_p;
3812         wldp_t  *infp;
3813         wldp_t *outfp;
3814         char *buf;
3815         int iret;
3816 
3817         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3818         if (buf == NULL) {
3819                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3820                     MAX_BUF_LEN));
3821                 return (ENOMEM);
3822         }
3823         outfp = (wldp_t *)buf;
3824         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3825         infp = (wldp_t *)mp->b_rptr;
3826         rf_p = &pcwl_p->pcwl_rf;
3827 
3828         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t);
3829         if (cmd == WLAN_GET_PARAM) {
3830                 *(wl_wep_key_id_t *)(outfp->wldp_buf) = rf_p->rf_tx_crypt_key;
3831                 outfp->wldp_result = WL_SUCCESS;
3832         } else if (cmd == WLAN_SET_PARAM) {
3833                 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf));
3834                 if (ret >= MAX_NWEPKEYS) {
3835                         outfp->wldp_length = WIFI_BUF_OFFSET;
3836                         outfp->wldp_result = WL_NOTSUPPORTED;
3837                         goto done;
3838                 }
3839                 rf_p->rf_tx_crypt_key = ret;
3840                 outfp->wldp_result = WL_SUCCESS;
3841         } else {
3842                 kmem_free(buf, MAX_BUF_LEN);
3843                 return (EINVAL);
3844         }
3845 done:
3846         for (i = 0; i < (outfp->wldp_length); i++)
3847                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3848         iret = (int)(outfp->wldp_result);
3849         kmem_free(buf, MAX_BUF_LEN);
3850         return (iret);
3851 }
3852 
3853 static int
3854 pcwl_cfg_createibss(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3855 {
3856         uint16_t        i;
3857         wldp_t          *infp;
3858         wldp_t          *outfp;
3859         char            *buf;
3860         int             iret;
3861         int             err = 0;
3862 
3863         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3864         if (buf == NULL) {
3865                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3866                     MAX_BUF_LEN));
3867                 return (ENOMEM);
3868         }
3869         outfp = (wldp_t *)buf;
3870         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3871         infp = (wldp_t *)mp->b_rptr;
3872 
3873         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t);
3874         if (cmd == WLAN_GET_PARAM) {
3875                 pcwl_get_ibss(pcwl_p, outfp->wldp_buf);
3876                 outfp->wldp_result = WL_SUCCESS;
3877         } else if (cmd == WLAN_SET_PARAM) {
3878                 err = pcwl_set_ibss(pcwl_p, infp->wldp_buf);
3879                 if (err == ENOTSUP) {
3880                         outfp->wldp_length = WIFI_BUF_OFFSET;
3881                         outfp->wldp_result = WL_NOTSUPPORTED;
3882                         goto done;
3883                 }
3884                 outfp->wldp_result = WL_SUCCESS;
3885         } else {
3886                 kmem_free(buf, MAX_BUF_LEN);
3887                 return (EINVAL);
3888         }
3889 done:
3890         for (i = 0; i < (outfp->wldp_length); i++)
3891                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3892         iret = (int)(outfp->wldp_result);
3893         kmem_free(buf, MAX_BUF_LEN);
3894         return (iret);
3895 }
3896 
3897 static int
3898 pcwl_cfg_rssi(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3899 {
3900         uint16_t i;
3901         int iret;
3902         wldp_t *outfp;
3903         char *buf;
3904 
3905         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3906         if (buf == NULL) {
3907                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3908                     MAX_BUF_LEN));
3909                 return (ENOMEM);
3910         }
3911         outfp = (wldp_t *)buf;
3912         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3913 
3914         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t);
3915 
3916         if (cmd == WLAN_GET_PARAM) {
3917                 pcwl_get_param_rssi(pcwl_p, outfp->wldp_buf);
3918                 outfp->wldp_result = WL_SUCCESS;
3919         } else if (cmd == WLAN_SET_PARAM) {
3920                 outfp->wldp_result = WL_READONLY;
3921         } else {
3922                 kmem_free(buf, MAX_BUF_LEN);
3923                 return (EINVAL);
3924         }
3925 done:
3926         for (i = 0; i < (outfp->wldp_length); i++)
3927                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3928         iret = (int)(outfp->wldp_result);
3929         kmem_free(buf, MAX_BUF_LEN);
3930         return (iret);
3931 }
3932 
3933 /*ARGSUSED*/
3934 static int
3935 pcwl_cfg_radio(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3936 {
3937         uint16_t i;
3938         int iret;
3939         wldp_t *outfp;
3940         char *buf;
3941 
3942         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3943         if (buf == NULL) {
3944                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3945                     MAX_BUF_LEN));
3946                 return (ENOMEM);
3947         }
3948         outfp = (wldp_t *)buf;
3949         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3950 
3951         if (cmd == WLAN_GET_PARAM) {
3952                 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE;
3953                 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t);
3954                 outfp->wldp_result = WL_SUCCESS;
3955         } else if (cmd == WLAN_SET_PARAM) {
3956                 outfp->wldp_length = WIFI_BUF_OFFSET;
3957                 outfp->wldp_result = WL_LACK_FEATURE;
3958         } else {
3959                 kmem_free(buf, MAX_BUF_LEN);
3960                 return (EINVAL);
3961         }
3962         for (i = 0; i < (outfp->wldp_length); i++)
3963                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3964         iret = (int)(outfp->wldp_result);
3965         kmem_free(buf, MAX_BUF_LEN);
3966         return (iret);
3967 }
3968 
3969 static int
3970 pcwl_cfg_wepkey(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3971 {
3972         uint16_t        i;
3973         wldp_t          *infp;
3974         wldp_t          *outfp;
3975         char            *buf;
3976         int             iret;
3977 
3978         buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3979         if (buf == NULL) {
3980                 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3981                     MAX_BUF_LEN));
3982                 return (ENOMEM);
3983         }
3984         outfp = (wldp_t *)buf;
3985         bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3986         infp = (wldp_t *)mp->b_rptr;
3987 
3988         outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_tab_t);
3989         if (cmd == WLAN_GET_PARAM) {
3990                 outfp->wldp_result = WL_WRITEONLY;
3991         } else if (cmd == WLAN_SET_PARAM) {
3992                 (void) pcwl_set_wepkey(pcwl_p, infp->wldp_buf);
3993                 outfp->wldp_result = WL_SUCCESS;
3994         } else {
3995                 kmem_free(buf, MAX_BUF_LEN);
3996                 return (EINVAL);
3997         }
3998 done:
3999         for (i = 0; i < (outfp->wldp_length); i++)
4000                 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4001         iret = (int)(outfp->wldp_result);
4002         kmem_free(buf, MAX_BUF_LEN);
4003         return (iret);
4004 }
4005 
4006 static void
4007 pcwl_connect_timeout(void *arg)
4008 {
4009         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
4010         uint16_t ret = 0;
4011 
4012         mutex_enter(&pcwl_p->pcwl_glock);
4013         PCWL_DISABLE_INTR(pcwl_p);
4014         if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4015                 goto done;
4016         }
4017         if (ret = pcwl_config_rf(pcwl_p)) {
4018                 goto done;
4019         }
4020         if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
4021                 goto done;
4022         }
4023         PCWL_ENABLE_INTR(pcwl_p);
4024 done:
4025         if (ret)
4026                 cmn_err(CE_WARN, "pcwl: connect failed due to hardware error");
4027         mutex_exit(&pcwl_p->pcwl_glock);
4028         pcwl_p->pcwl_connect_timeout_id = 0;
4029 }
4030 
4031 static int
4032 pcwl_getset(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
4033 {
4034         int ret = WL_SUCCESS;
4035         int connect = 0;
4036 
4037         mutex_enter(&pcwl_p->pcwl_glock);
4038         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
4039                 mutex_exit(&pcwl_p->pcwl_glock);
4040                 return (PCWL_FAIL);
4041         }
4042         switch (((wldp_t *)mp->b_rptr)->wldp_id) {
4043         case WL_ESSID:
4044                 ret = pcwl_cfg_essid(mp, pcwl_p, cmd);
4045                 connect = 1;
4046                 PCWLDBG((CE_NOTE, "cfg_essid\n"));
4047                 break;
4048         case WL_BSSID:
4049                 ret = pcwl_cfg_bssid(mp, pcwl_p, cmd);
4050                 connect = 1;
4051                 PCWLDBG((CE_NOTE, "cfg_bssid\n"));
4052                 break;
4053         case WL_ESS_LIST:
4054                 ret = pcwl_cfg_scan(mp, pcwl_p, cmd);
4055                 PCWLDBG((CE_NOTE, "cfg_scan\n"));
4056                 break;
4057         case WL_LINKSTATUS:
4058                 ret = pcwl_cfg_linkstatus(mp, pcwl_p, cmd);
4059                 PCWLDBG((CE_NOTE, "cfg_linkstatus\n"));
4060                 break;
4061         case WL_BSS_TYPE:
4062                 ret = pcwl_cfg_bsstype(mp, pcwl_p, cmd);
4063                 connect = 1;
4064                 PCWLDBG((CE_NOTE, "cfg_bsstype\n"));
4065                 break;
4066         case WL_PHY_CONFIG:
4067                 ret = pcwl_cfg_phy(mp, pcwl_p, cmd);
4068                 connect = 1;
4069                 PCWLDBG((CE_NOTE, "cfg_phy\n"));
4070                 break;
4071         case WL_DESIRED_RATES:
4072                 ret = pcwl_cfg_desiredrates(mp, pcwl_p, cmd);
4073                 connect = 1;
4074                 PCWLDBG((CE_NOTE, "cfg_disred-rates\n"));
4075                 break;
4076         case WL_SUPPORTED_RATES:
4077                 ret = pcwl_cfg_supportrates(mp, pcwl_p, cmd);
4078                 PCWLDBG((CE_NOTE, "cfg_supported-rates\n"));
4079                 break;
4080         case WL_POWER_MODE:
4081                 ret = pcwl_cfg_powermode(mp, pcwl_p, cmd);
4082                 PCWLDBG((CE_NOTE, "cfg_powermode\n"));
4083                 break;
4084         case WL_AUTH_MODE:
4085                 ret = pcwl_cfg_authmode(mp, pcwl_p, cmd);
4086                 connect = 1;
4087                 PCWLDBG((CE_NOTE, "cfg_authmode\n"));
4088                 break;
4089         case WL_ENCRYPTION:
4090                 ret = pcwl_cfg_encryption(mp, pcwl_p, cmd);
4091                 connect = 1;
4092                 PCWLDBG((CE_NOTE, "cfg_encryption\n"));
4093                 break;
4094         case WL_WEP_KEY_ID:
4095                 ret = pcwl_cfg_wepkeyid(mp, pcwl_p, cmd);
4096                 connect = 1;
4097                 PCWLDBG((CE_NOTE, "cfg_wepkeyid\n"));
4098                 break;
4099         case WL_CREATE_IBSS:
4100                 ret = pcwl_cfg_createibss(mp, pcwl_p, cmd);
4101                 connect = 1;
4102                 PCWLDBG((CE_NOTE, "cfg_create-ibss\n"));
4103                 break;
4104         case WL_RSSI:
4105                 ret = pcwl_cfg_rssi(mp, pcwl_p, cmd);
4106                 PCWLDBG((CE_NOTE, "cfg_rssi\n"));
4107                 break;
4108         case WL_RADIO:
4109                 ret = pcwl_cfg_radio(mp, pcwl_p, cmd);
4110                 PCWLDBG((CE_NOTE, "cfg_radio\n"));
4111                 break;
4112         case WL_WEP_KEY_TAB:
4113                 ret = pcwl_cfg_wepkey(mp, pcwl_p, cmd);
4114                 connect = 1;
4115                 PCWLDBG((CE_NOTE, "cfg_wepkey\n"));
4116                 break;
4117         case WL_SCAN:
4118                 mutex_exit(&pcwl_p->pcwl_glock);
4119                 if (pcwl_p->pcwl_connect_timeout_id != 0) {
4120                         (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4121                         pcwl_p->pcwl_connect_timeout_id = 0;
4122                 }
4123                 mutex_enter(&pcwl_p->pcwl_glock);
4124                 ret = pcwl_cmd_scan(pcwl_p);
4125                 break;
4126         case WL_LOAD_DEFAULTS:
4127                 mutex_exit(&pcwl_p->pcwl_glock);
4128                 if (pcwl_p->pcwl_connect_timeout_id != 0) {
4129                         (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4130                         pcwl_p->pcwl_connect_timeout_id = 0;
4131                 }
4132                 mutex_enter(&pcwl_p->pcwl_glock);
4133                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4134                         ret = (int)WL_HW_ERROR;
4135                         break;
4136                 }
4137                 if (ret = pcwl_loaddef_rf(pcwl_p)) {
4138                         ret = (int)WL_HW_ERROR;
4139                         PCWLDBG((CE_WARN, "cfg_loaddef_err\n"));
4140                         break;
4141                 }
4142                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
4143                         ret = (int)WL_HW_ERROR;
4144                         break;
4145                 }
4146                 pcwl_delay(pcwl_p, 1000000);
4147                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4148                         ret = (int)WL_HW_ERROR;
4149                         break;
4150                 }
4151                 PCWLDBG((CE_NOTE, "loaddef\n"));
4152                 break;
4153         case WL_DISASSOCIATE:
4154                 mutex_exit(&pcwl_p->pcwl_glock);
4155                 if (pcwl_p->pcwl_connect_timeout_id != 0) {
4156                         (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4157                         pcwl_p->pcwl_connect_timeout_id = 0;
4158                 }
4159 
4160                 mutex_enter(&pcwl_p->pcwl_glock);
4161                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4162                         ret = (int)WL_HW_ERROR;
4163                         break;
4164                 }
4165                 /*
4166                  * A workaround here: If the card is in ad-hoc mode, the
4167                  * following scan will not work correctly, so any
4168                  * 'dladm connect-wifi' which need a scan first will not
4169                  * succeed. software reset the card here as a workround.
4170                  */
4171                 if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) &&
4172                     (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) {
4173                         if (ret = pcwl_reset_backend(pcwl_p)) {
4174                                 ret = (int)WL_HW_ERROR;
4175                                 break;
4176                         }
4177                         if (ret = pcwl_init_nicmem(pcwl_p)) {
4178                                 ret = (int)WL_HW_ERROR;
4179                                 break;
4180                         }
4181                         pcwl_start_locked(pcwl_p);
4182                 }
4183                 if (ret = pcwl_loaddef_rf(pcwl_p)) {
4184                         ret = (int)WL_HW_ERROR;
4185                         PCWLDBG((CE_WARN, "cfg_loaddef_err\n"));
4186                         break;
4187                 }
4188                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
4189                         ret = (int)WL_HW_ERROR;
4190                         break;
4191                 }
4192                 pcwl_delay(pcwl_p, 1000000);
4193                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4194                         ret = (int)WL_HW_ERROR;
4195                         break;
4196                 }
4197                 PCWLDBG((CE_NOTE, "disassociate\n"));
4198                 break;
4199         case WL_REASSOCIATE:
4200         case WL_ASSOCIAT:
4201                 mutex_exit(&pcwl_p->pcwl_glock);
4202                 if (pcwl_p->pcwl_connect_timeout_id != 0) {
4203                         (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4204                         pcwl_p->pcwl_connect_timeout_id = 0;
4205                 }
4206                 mutex_enter(&pcwl_p->pcwl_glock);
4207                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4208                         ret = (int)WL_HW_ERROR;
4209                         break;
4210                 }
4211                 if (ret = pcwl_config_rf(pcwl_p)) {
4212                         ret = (int)WL_HW_ERROR;
4213                         break;
4214                 }
4215                 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
4216                         ret = (int)WL_HW_ERROR;
4217                         break;
4218                 }
4219                 PCWLDBG((CE_NOTE, "associate"));
4220                 break;
4221         default:
4222                 break;
4223         }
4224         mutex_exit(&pcwl_p->pcwl_glock);
4225         if ((cmd == WLAN_SET_PARAM) && (connect)) {
4226                 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
4227                 if (pcwl_p->pcwl_connect_timeout_id != 0) {
4228                         (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4229                         pcwl_p->pcwl_connect_timeout_id = 0;
4230                 }
4231                 pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout,
4232                     pcwl_p, 2 * drv_usectohz(1000000));
4233         }
4234         return (ret);
4235 }
4236 
4237 static void
4238 pcwl_wlan_ioctl(pcwl_maci_t *pcwl_p, queue_t *wq, mblk_t *mp, uint32_t cmd)
4239 {
4240 
4241         struct  iocblk  *iocp = (struct iocblk *)mp->b_rptr;
4242         wldp_t  *infp;
4243         uint32_t len, ret;
4244         mblk_t          *mp1;
4245 
4246         /*
4247          * sanity check
4248          */
4249         if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) {
4250                 miocnak(wq, mp, 0, EINVAL);
4251                 return;
4252         }
4253 
4254         /*
4255          * assuming single data block
4256          */
4257         if (mp1->b_cont) {
4258                 freemsg(mp1->b_cont);
4259                 mp1->b_cont = NULL;
4260         }
4261 
4262         /*
4263          * we will overwrite everything
4264          */
4265         mp1->b_wptr = mp1->b_rptr;
4266 
4267         infp = (wldp_t *)mp1->b_rptr;
4268         PCWLDBG((CE_NOTE, "pcwl: wldp->length=0x%x\n", infp->wldp_length));
4269         PCWLDBG((CE_NOTE, "pcwl: wldp->type =:%s\n",
4270             infp->wldp_type == NET_802_11 ? "NET_802_11" : "Unknown"));
4271         PCWLDBG((CE_NOTE, "pcwl: wldp->id=0x%x\n", infp->wldp_id));
4272         PCWLDBG((CE_NOTE, "pcwl: wldp->result=0x%x\n", infp->wldp_result));
4273 
4274         ret = pcwl_getset(mp1, pcwl_p, cmd);
4275         len = msgdsize(mp1);
4276         PCWLDBG((CE_CONT, "pcwl: ioctl message length = %d\n", len));
4277         miocack(wq, mp, len, ret);
4278 
4279 }
4280 
4281 
4282 static void
4283 pcwl_ioctl(void *arg, queue_t *wq, mblk_t *mp)
4284 {
4285         struct iocblk *iocp;
4286         uint32_t cmd, ret;
4287         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
4288         boolean_t need_privilege = B_TRUE;
4289 
4290         /*
4291          * Validate the command before bothering with the mutexen ...
4292          */
4293         iocp = (struct iocblk *)mp->b_rptr;
4294         iocp->ioc_error = 0;
4295         cmd = iocp->ioc_cmd;
4296         switch (cmd) {
4297         default:
4298                 PCWLDBG((CE_CONT, "pcwl_ioctl: unknown cmd 0x%x", cmd));
4299                 miocnak(wq, mp, 0, EINVAL);
4300                 return;
4301         case WLAN_GET_PARAM:
4302                 need_privilege = B_FALSE;
4303                 break;
4304         case WLAN_SET_PARAM:
4305         case WLAN_COMMAND:
4306                 break;
4307         }
4308 
4309         if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0)
4310                 miocnak(wq, mp, 0, ret);
4311         else
4312                 pcwl_wlan_ioctl(pcwl_p, wq, mp, cmd);
4313 }
4314 
4315 /*
4316  * brussels
4317  */
4318 /* ARGSUSED */
4319 static int
4320 pcwl_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4321     uint_t wldp_length, const void *wldp_buf)
4322 {
4323         int             err = 0;
4324         pcwl_maci_t     *pcwl_p = (pcwl_maci_t *)arg;
4325 
4326         mutex_enter(&pcwl_p->pcwl_glock);
4327         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
4328                 mutex_exit(&pcwl_p->pcwl_glock);
4329                 err = EINVAL;
4330                 return (err);
4331         }
4332 
4333         switch (wldp_pr_num) {
4334         /* mac_prop_id */
4335         case MAC_PROP_WL_ESSID:
4336                 err = pcwl_set_essid(pcwl_p, wldp_buf);
4337                 break;
4338         case MAC_PROP_WL_PHY_CONFIG:
4339                 err = pcwl_set_phy(pcwl_p, wldp_buf);
4340                 break;
4341         case MAC_PROP_WL_KEY_TAB:
4342                 err = pcwl_set_wepkey(pcwl_p, wldp_buf);
4343                 break;
4344         case MAC_PROP_WL_AUTH_MODE:
4345                 err = pcwl_set_authmode(pcwl_p, wldp_buf);
4346                 break;
4347         case MAC_PROP_WL_ENCRYPTION:
4348                 err = pcwl_set_encrypt(pcwl_p, wldp_buf);
4349                 break;
4350         case MAC_PROP_WL_BSSTYPE:
4351                 err = pcwl_set_bsstype(pcwl_p, wldp_buf);
4352                 break;
4353         case MAC_PROP_WL_DESIRED_RATES:
4354                 err = pcwl_set_desrates(pcwl_p, wldp_buf);
4355                 break;
4356         case MAC_PROP_WL_POWER_MODE:
4357                 err = pcwl_set_powermode(pcwl_p, wldp_buf);
4358                 break;
4359         case MAC_PROP_WL_CREATE_IBSS:
4360                 err = pcwl_set_ibss(pcwl_p, wldp_buf);
4361                 break;
4362         case MAC_PROP_WL_BSSID:
4363         case MAC_PROP_WL_RADIO:
4364         case MAC_PROP_WL_WPA:
4365         case MAC_PROP_WL_KEY:
4366         case MAC_PROP_WL_DELKEY:
4367         case MAC_PROP_WL_SETOPTIE:
4368         case MAC_PROP_WL_MLME:
4369         case MAC_PROP_WL_LINKSTATUS:
4370         case MAC_PROP_WL_ESS_LIST:
4371         case MAC_PROP_WL_SUPPORTED_RATES:
4372         case MAC_PROP_WL_RSSI:
4373         case MAC_PROP_WL_CAPABILITY:
4374         case MAC_PROP_WL_SCANRESULTS:
4375                 cmn_err(CE_WARN, "pcwl_setprop:"
4376                     "opmode not support\n");
4377                 err = ENOTSUP;
4378                 break;
4379         default:
4380                 cmn_err(CE_WARN, "pcwl_setprop:"
4381                     "opmode err\n");
4382                 err = EINVAL;
4383                 break;
4384         }
4385 
4386         mutex_exit(&pcwl_p->pcwl_glock);
4387 
4388         if (err == ENETRESET) {
4389                 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
4390                 if (pcwl_p->pcwl_connect_timeout_id != 0) {
4391                         (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4392                         pcwl_p->pcwl_connect_timeout_id = 0;
4393                 }
4394                 pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout,
4395                     pcwl_p, 2 * drv_usectohz(1000000));
4396 
4397                 err = 0;
4398         }
4399 
4400         return (err);
4401 } /* ARGSUSED */
4402 
4403 /* ARGSUSED */
4404 static int
4405 pcwl_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4406     uint_t wldp_length, void *wldp_buf)
4407 {
4408         int err = 0;
4409         pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
4410 
4411         mutex_enter(&pcwl_p->pcwl_glock);
4412         if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
4413                 mutex_exit(&pcwl_p->pcwl_glock);
4414                 err = EINVAL;
4415                 return (err);
4416         }
4417 
4418         switch (wldp_pr_num) {
4419         /* mac_prop_id */
4420         case MAC_PROP_WL_ESSID:
4421                 err = pcwl_get_essid(pcwl_p, wldp_buf);
4422                 break;
4423         case MAC_PROP_WL_BSSID:
4424                 err = pcwl_get_bssid(pcwl_p, wldp_buf);
4425                 break;
4426         case MAC_PROP_WL_PHY_CONFIG:
4427                 err = pcwl_get_phy(pcwl_p, wldp_buf);
4428                 break;
4429         case MAC_PROP_WL_AUTH_MODE:
4430                 pcwl_get_authmode(pcwl_p, wldp_buf);
4431                 break;
4432         case MAC_PROP_WL_ENCRYPTION:
4433                 pcwl_get_encrypt(pcwl_p, wldp_buf);
4434                 break;
4435         case MAC_PROP_WL_BSSTYPE:
4436                 pcwl_get_bsstype(pcwl_p, wldp_buf);
4437                 break;
4438         case MAC_PROP_WL_LINKSTATUS:
4439                 err = pcwl_get_linkstatus(pcwl_p, wldp_buf);
4440                 break;
4441         case MAC_PROP_WL_ESS_LIST:
4442                 pcwl_get_esslist(pcwl_p, wldp_buf);
4443                 break;
4444         case MAC_PROP_WL_SUPPORTED_RATES:
4445                 pcwl_get_suprates(wldp_buf);
4446                 break;
4447         case MAC_PROP_WL_RSSI:
4448                 pcwl_get_param_rssi(pcwl_p, wldp_buf);
4449                 break;
4450         case MAC_PROP_WL_RADIO:
4451                 pcwl_get_radio(wldp_buf);
4452                 break;
4453         case MAC_PROP_WL_POWER_MODE:
4454                 pcwl_get_powermode(pcwl_p, wldp_buf);
4455                 break;
4456         case MAC_PROP_WL_CREATE_IBSS:
4457                 pcwl_get_ibss(pcwl_p, wldp_buf);
4458                 break;
4459         case MAC_PROP_WL_DESIRED_RATES:
4460                 err = pcwl_get_desrates(pcwl_p, wldp_buf);
4461                 break;
4462         case MAC_PROP_WL_CAPABILITY:
4463         case MAC_PROP_WL_WPA:
4464         case MAC_PROP_WL_SCANRESULTS:
4465         case MAC_PROP_WL_KEY_TAB:
4466         case MAC_PROP_WL_KEY:
4467         case MAC_PROP_WL_DELKEY:
4468         case MAC_PROP_WL_SETOPTIE:
4469         case MAC_PROP_WL_MLME:
4470                 cmn_err(CE_WARN, "pcwl_getprop:"
4471                     "opmode not support\n");
4472                 err = ENOTSUP;
4473                 break;
4474         default:
4475                 cmn_err(CE_WARN, "pcwl_getprop:"
4476                     "opmode err\n");
4477                 err = EINVAL;
4478                 break;
4479         }
4480 
4481         mutex_exit(&pcwl_p->pcwl_glock);
4482 
4483         return (err);
4484 }
4485 
4486 
4487 static void
4488 pcwl_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wlpd_pr_num,
4489     mac_prop_info_handle_t prh)
4490 {
4491         _NOTE(ARGUNUSED(arg, pr_name));
4492 
4493         switch (wlpd_pr_num) {
4494         case MAC_PROP_WL_LINKSTATUS:
4495         case MAC_PROP_WL_ESS_LIST:
4496         case MAC_PROP_WL_SUPPORTED_RATES:
4497         case MAC_PROP_WL_RSSI:
4498                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
4499         }
4500 }
4501 
4502 
4503 /*
4504  * quiesce(9E) entry point.
4505  *
4506  * This function is called when the system is single-threaded at high
4507  * PIL with preemption disabled. Therefore, this function must not be
4508  * blocked.
4509  *
4510  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4511  * DDI_FAILURE indicates an error condition and should almost never happen.
4512  */
4513 #ifndef __sparc
4514 static int
4515 pcwl_quiesce(dev_info_t *dip)
4516 {
4517         pcwl_maci_t *pcwl_p;
4518 
4519         pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip));
4520         if (pcwl_p == NULL)
4521                 return (DDI_FAILURE);
4522 
4523         if (pcwl_p->pcwl_flag & PCWL_CARD_READY)
4524                 pcwl_stop_locked(pcwl_p);
4525 
4526         return (DDI_SUCCESS);
4527 }
4528 #endif