1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Wire Adapter Operations
  28  * Both DWA and HWA have the same kind of functional components, the
  29  * Wire Adapter. Functions defined in this file are to handle WA's
  30  * class specific Descriptors, Requests, Notifications and Transfers.
  31  * DWA or HWA specific descriptors, requests are not handled here.
  32  */
  33 
  34 #include <sys/usb/hwa/hwahc/hwahc.h>
  35 #include <sys/usb/hwa/hwahc/hwahc_util.h>
  36 #include <sys/usb/usba/wa.h>
  37 #include <sys/usb/usba/wusba.h>
  38 #include <sys/usb/usba/whcdi.h>
  39 #include <sys/usb/usba.h>
  40 #include <sys/usb/usba/usba_impl.h>
  41 #include <sys/usb/usba/usba_devdb.h>      /* usba_devdb_refresh */
  42 #include <sys/usb/hubd/hubdvar.h>
  43 #include <sys/usb/hubd/hubd_impl.h>       /* hubd_ioctl_data_t */
  44 #include <sys/strsubr.h>  /* allocb_wait */
  45 #include <sys/strsun.h>           /* MBLKL macro */
  46 
  47 extern usb_log_handle_t whcdi_log_handle;
  48 
  49 /* default rpipe PHY transfer speed */
  50 static uint8_t rp_default_speed = WUSB_PHY_TX_RATE_106;
  51 
  52 /* function prototypes */
  53 static void wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl,
  54         wusb_wa_trans_wrapper_t *tw);
  55 static void wusb_wa_handle_error(wusb_wa_data_t *wa_data,
  56         wusb_wa_trans_wrapper_t *wr, usb_cr_t cr);
  57 
  58 /*
  59  * Parse Wire Adapter class desriptor.
  60  *      - see 8.4.3.7 & 8.5.2.7
  61  *
  62  *      wa_descr - the parsed descriptors.
  63  *      altif_data - the passed in raw descriptor data.
  64  */
  65 int
  66 wusb_parse_wa_descr(usb_wa_descr_t *wa_descr, usb_alt_if_data_t *altif_data)
  67 {
  68         usb_cvs_data_t  *cvs_data;
  69         int             i;
  70         size_t          count;
  71 
  72         if ((wa_descr == NULL) || (altif_data == NULL)) {
  73                 return (USB_INVALID_ARGS);
  74         }
  75 
  76         for (i = 0; i < altif_data->altif_n_cvs; i++) {
  77                 cvs_data = &altif_data->altif_cvs[i];
  78                 if (cvs_data->cvs_buf == NULL) {
  79                         continue;
  80                 }
  81                 if (cvs_data->cvs_buf[1] == USB_DESCR_TYPE_WA) {
  82                         count = usb_parse_data("ccsccsscccc",
  83                             cvs_data->cvs_buf, cvs_data->cvs_buf_len,
  84                             (void *)wa_descr,
  85                             (size_t)USB_WA_DESCR_SIZE);
  86                         if (count != USB_WA_DESCR_SIZE) {
  87                                 return (USB_FAILURE);
  88                         } else {
  89                                 return (USB_SUCCESS);
  90                         }
  91                 }
  92         }
  93 
  94         return (USB_FAILURE);
  95 }
  96 
  97 /* initialize rpipe structures */
  98 void
  99 wusb_wa_rpipes_init(wusb_wa_data_t *wa_data)
 100 {
 101         int                     i;
 102         wusb_wa_rpipe_hdl_t     *hdl;
 103 
 104         for (i = 0; i < wa_data->wa_num_rpipes; i++) {
 105                 hdl = &wa_data->wa_rpipe_hdl[i];
 106                 mutex_init(&hdl->rp_mutex, NULL, MUTEX_DRIVER, NULL);
 107                 cv_init(&hdl->rp_cv, NULL, CV_DRIVER, NULL);
 108 
 109                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdl));
 110                 hdl->rp_state = WA_RPIPE_STATE_FREE;
 111                 hdl->rp_refcnt = 0;
 112                 hdl->rp_timeout_list = NULL;
 113                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*hdl));
 114         }
 115 }
 116 
 117 /* deinitialize rpipe structures */
 118 void
 119 wusb_wa_rpipes_fini(wusb_wa_data_t *wa_data)
 120 {
 121         int                     i;
 122         wusb_wa_rpipe_hdl_t     *hdl;
 123 
 124         for (i = 0; i < wa_data->wa_num_rpipes; i++) {
 125                 hdl = &wa_data->wa_rpipe_hdl[i];
 126                 mutex_destroy(&hdl->rp_mutex);
 127                 cv_destroy(&hdl->rp_cv);
 128         }
 129 }
 130 
 131 
 132 /*
 133  * wusb_wa_data_init:
 134  *      WA interface validation
 135  *      Parse WA class descriptors
 136  *      Set up RPipes
 137  *      Set up callbacks
 138  */
 139 int
 140 wusb_wa_data_init(dev_info_t *dip, wusb_wa_data_t *wa_data, wusb_wa_cb_t *cbs,
 141         usb_client_dev_data_t *dev_data,
 142         uint_t mask, usb_log_handle_t handle)
 143 {
 144         usb_alt_if_data_t       *altif_data;
 145         usb_ep_data_t           *ep_data;
 146         int                     ifno;
 147         int                     rval;
 148 
 149         if ((wa_data == NULL) || (dev_data == NULL)) {
 150 
 151                 return (USB_INVALID_ARGS);
 152         }
 153 
 154         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data));
 155 
 156         /* get inf descr and ept descrs from altif data */
 157         altif_data = &dev_data->dev_curr_cfg->
 158             cfg_if[dev_data->dev_curr_if].if_alt[0];
 159 
 160         /* T.8-44. Wire Adapter */
 161         if (altif_data->altif_descr.bInterfaceSubClass !=
 162             USB_SUBCLS_WUSB_2) {
 163                 USB_DPRINTF_L2(mask, handle,
 164                     "wusb_init_wa_data: invalid interface subclass (0x%x)",
 165                     altif_data->altif_descr.bInterfaceSubClass);
 166 
 167                 return (USB_FAILURE);
 168         }
 169 
 170         /* at least 3 EPs, INTR IN + BULK IN + BULK OUT */
 171         if (altif_data->altif_n_ep < 3) {
 172                 USB_DPRINTF_L2(mask, handle,
 173                     "wusb_init_wa_data: invalid alt 0 for interface %d",
 174                     dev_data->dev_curr_if);
 175 
 176                 return (USB_FAILURE);
 177         }
 178 
 179         wa_data->wa_ifno = ifno = dev_data->dev_curr_if;
 180         wa_data->wa_if_descr = altif_data->altif_descr;
 181 
 182         if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
 183             USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
 184                 wa_data->wa_bulkout_ept = ep_data->ep_descr;
 185         }
 186         if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
 187             USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
 188                 wa_data->wa_bulkin_ept = ep_data->ep_descr;
 189         }
 190         if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
 191             USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
 192                 wa_data->wa_intr_ept = ep_data->ep_descr;
 193         }
 194 
 195         if ((wa_data->wa_bulkout_ept.bLength == 0) ||
 196             (wa_data->wa_bulkin_ept.bLength == 0) ||
 197             (wa_data->wa_intr_ept.bLength == 0)) {
 198                 USB_DPRINTF_L2(mask, handle,
 199                     "wusb_init_wa_data: the minimum endpoint set is not "
 200                     "supported");
 201 
 202                 return (USB_FAILURE);
 203         }
 204 
 205         /* parse the WA descriptor */
 206         if ((rval = wusb_parse_wa_descr(&wa_data->wa_descr, altif_data)) !=
 207             USB_SUCCESS) {
 208                 USB_DPRINTF_L2(mask, handle,
 209                     "wusb_init_wa_data: parse wire adapter class descr failed");
 210 
 211                 return (rval);
 212         }
 213         wa_data->wa_avail_blocks = wa_data->wa_descr.wRPipeMaxBlock;
 214 
 215         wa_data->wa_dip = dip;
 216 
 217         /* initialize rpipe handlers */
 218         wa_data->wa_num_rpipes = wa_data->wa_descr.wNumRPipes;
 219 
 220         wa_data->wa_rpipe_hdl = kmem_zalloc((wa_data->wa_num_rpipes *
 221             sizeof (wusb_wa_rpipe_hdl_t)), KM_SLEEP);
 222 
 223         /* init rpipes */
 224         wusb_wa_rpipes_init(wa_data);
 225 
 226         /* register callbacks */
 227         wa_data->pipe_periodic_req = cbs->pipe_periodic_req;
 228         wa_data->intr_cb = cbs->intr_cb;
 229         wa_data->intr_exc_cb = cbs->intr_exc_cb;
 230         wa_data->rpipe_xfer_cb = cbs->rpipe_xfer_cb;
 231 
 232         mutex_init(&wa_data->wa_mutex, NULL, MUTEX_DRIVER, NULL);
 233 
 234         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data));
 235 
 236         return (USB_SUCCESS);
 237 }
 238 
 239 /* deinitialize data transfer related resources */
 240 void
 241 wusb_wa_data_fini(wusb_wa_data_t *wa_data)
 242 {
 243         mutex_enter(&wa_data->wa_mutex);
 244         if (wa_data->wa_rpipe_hdl) {
 245                 wusb_wa_rpipes_fini(wa_data);
 246                 kmem_free(wa_data->wa_rpipe_hdl, wa_data->wa_num_rpipes *
 247                     sizeof (wusb_wa_rpipe_hdl_t));
 248         }
 249         mutex_exit(&wa_data->wa_mutex);
 250         mutex_destroy(&wa_data->wa_mutex);
 251 }
 252 
 253 void wusb_wa_dump_rpipe_descr(usb_wa_rpipe_descr_t *pd, uint_t mask,
 254     usb_log_handle_t handle)
 255 {
 256         USB_DPRINTF_L4(mask, handle, "RPipe Descriptor:\n"
 257             "\tWRPipeIndex=%d wRequests=%d wBlocks=%d\n"
 258             "\twMaxPacketSize=%d bHSHubAddress=%d\n"
 259             "\tbHSHubPort=%d bSpeed=%d bDeviceAddress=%d\n"
 260             "\tbEndpointAddress=0x%02x bDataSequence=%d\n"
 261             "\tdwCurrentWindow=0x%08x bMaxDataSequence=%d",
 262             pd->wRPipeIndex, pd->wRequests, pd->wBlocks, pd->wMaxPacketSize,
 263             pd->wa_value.hwa_value.bMaxBurst,
 264             pd->wa_value.hwa_value.bDeviceInfoIndex,
 265             pd->bSpeed, pd->bDeviceAddress,
 266             pd->bEndpointAddress, pd->bDataSequence, pd->dwCurrentWindow,
 267             pd->bMaxDataSequence);
 268 
 269         USB_DPRINTF_L4(mask, handle,
 270             "(cont'ed)bInterval=%d bOverTheAirInterval=%d\n"
 271             "\tbmAttribute=0x%02x bmCharacter=0x%02x\n"
 272             "\tbmRetryOptions=0x%02x wNumTransactionErrors=%d\n",
 273             pd->bInterval, pd->bOverTheAirInterval,
 274             pd->bmAttribute, pd->bmCharacteristics, pd->bmRetryOptions,
 275             pd->wNumTransactionErrors);
 276 
 277 }
 278 
 279 /* get rpipe descr of a certain index, refer to WUSB 1.0/8.3.1.4 */
 280 int
 281 wusb_wa_get_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph,
 282         uint16_t idx, usb_wa_rpipe_descr_t *descr,
 283         uint_t mask, usb_log_handle_t handle)
 284 {
 285         mblk_t          *data = NULL;
 286         usb_cr_t        completion_reason;
 287         usb_cb_flags_t  cb_flags;
 288         size_t          count;
 289         int             rval;
 290 
 291         /*
 292          * This descriptor is critical for later operations to succeed.
 293          * So, we must wait here.
 294          */
 295         rval = usb_pipe_sync_ctrl_xfer(dip, ph,
 296             WA_CLASS_RPIPE_REQ_IN_TYPE,
 297             USB_REQ_GET_DESCR,
 298             USB_DESCR_TYPE_RPIPE << 8,
 299             idx,
 300             USB_RPIPE_DESCR_SIZE,
 301             &data, 0,
 302             &completion_reason, &cb_flags, 0);
 303 
 304         if (rval != USB_SUCCESS) {
 305                 USB_DPRINTF_L2(mask, handle,
 306                     "wusb_wa_get_rpipe_descr: rval=%d, cr=%d, "
 307                     "cb=0x%x", rval, completion_reason, cb_flags);
 308 
 309                 goto done;
 310         }
 311 
 312         if (MBLKL(data) != USB_RPIPE_DESCR_SIZE) {
 313                 USB_DPRINTF_L2(mask, handle,
 314                     "wusb_wa_get_rpipe_descr: return size %d",
 315                     (int)MBLKL(data));
 316                 rval = USB_FAILURE;
 317 
 318                 goto done;
 319         }
 320 
 321         count = usb_parse_data("2c4s6cl6cs", data->b_rptr,
 322             USB_RPIPE_DESCR_SIZE, descr, sizeof (usb_wa_rpipe_descr_t));
 323 
 324         if (count == USB_PARSE_ERROR) {
 325                 USB_DPRINTF_L2(mask, handle,
 326                     "wusb_wa_get_rpipe_descr: parse error");
 327                 rval = USB_FAILURE;
 328 
 329                 goto done;
 330         }
 331 
 332         wusb_wa_dump_rpipe_descr(descr, mask, handle);
 333 
 334         freemsg(data);
 335         data = NULL;
 336 
 337         return (USB_SUCCESS);
 338 
 339 done:
 340         if (data) {
 341                 freemsg(data);
 342         }
 343 
 344         return (rval);
 345 }
 346 
 347 /*
 348  * Get All the RPipes' descriptors of an HWA
 349  *      - WA RPipe descriptor are not returned as part of the
 350  *      cofiguration descriptor. We have to get it separately.
 351  *      - See section 8.4.3.19 and 8.5.2.11
 352  */
 353 int
 354 wusb_wa_get_rpipe_descrs(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
 355         uint_t mask, usb_log_handle_t handle)
 356 {
 357         dev_info_t      *dip = wa_data->wa_dip;
 358         int             i, rval;
 359 
 360         if ((dip == NULL) || (ph == NULL)) {
 361 
 362                 return (USB_INVALID_ARGS);
 363         }
 364 
 365         /* called at initialization, no other threads yet */
 366         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data));
 367 
 368         for (i = 0; i < wa_data->wa_num_rpipes; i++) {
 369                 rval = wusb_wa_get_rpipe_descr(dip, ph, i,
 370                     &wa_data->wa_rpipe_hdl[i].rp_descr, mask, handle);
 371 
 372                 if (rval != USB_SUCCESS) {
 373                         USB_DPRINTF_L2(mask, handle,
 374                             "wusb_wa_get_rpipe_descrs: fail to get rpipe "
 375                             "descr for idx %d", i);
 376 
 377                         return (rval);
 378                 }
 379         }
 380         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data));
 381 
 382         return (USB_SUCCESS);
 383 }
 384 
 385 /*
 386  * Get Wire Adapter's Status
 387  *      See section 8.3.1.6
 388  */
 389 int
 390 wusb_get_wa_status(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
 391         uint32_t *status)
 392 {
 393         dev_info_t      *dip = wa_data->wa_dip;
 394         int             rval = USB_SUCCESS;
 395         mblk_t          *data = NULL;
 396         usb_cr_t        completion_reason;
 397         usb_cb_flags_t  cb_flags;
 398 
 399         if ((dip == NULL) || (ph == NULL)) {
 400 
 401                 return (USB_INVALID_ARGS);
 402         }
 403 
 404         rval = usb_pipe_sync_ctrl_xfer(dip, ph,
 405             WUSB_CLASS_IF_REQ_IN_TYPE,
 406             USB_REQ_GET_STATUS,
 407             0,
 408             wa_data->wa_ifno,
 409             WA_GET_WA_STATUS_LEN,
 410             &data, 0,
 411             &completion_reason, &cb_flags, 0);
 412 
 413         if (rval != USB_SUCCESS) {
 414                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
 415                     "wusb_get_wa_status: can't retrieve status");
 416 
 417                 goto done;
 418         }
 419 
 420         *status = (*(data->b_rptr + 3) << 24) | (*(data->b_rptr + 2) << 16) |
 421             (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
 422 
 423 done:
 424         if (data) {
 425                 freemsg(data);
 426         }
 427 
 428         return (rval);
 429 }
 430 
 431 /*
 432  * Reset WA
 433  *      See 8.3.1.9
 434  */
 435 int
 436 wusb_wa_reset(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
 437 {
 438         dev_info_t      *dip = wa_data->wa_dip;
 439         usb_cr_t        completion_reason;
 440         usb_cb_flags_t  cb_flags;
 441         int             rval, i;
 442         uint32_t        status;
 443 
 444         if ((dip == NULL) || (ph == NULL)) {
 445 
 446                 return (USB_INVALID_ARGS);
 447         }
 448 
 449         rval = usb_pipe_sync_ctrl_xfer(dip, ph,
 450             WUSB_CLASS_IF_REQ_OUT_TYPE,
 451             USB_REQ_SET_FEATURE,
 452             WA_DEV_RESET,
 453             wa_data->wa_ifno,
 454             0,
 455             NULL, 0,
 456             &completion_reason, &cb_flags, 0);
 457 
 458         if (rval != USB_SUCCESS) {
 459                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
 460                     "wusb_wa_reset: can't reset wa, rval = %d, cr=%d", rval,
 461                     completion_reason);
 462 
 463                 return (rval);
 464         }
 465 
 466         for (i = 0; i < 10; i++) {
 467                 delay(drv_usectohz(50000));
 468 
 469                 rval = wusb_get_wa_status(wa_data, ph, &status);
 470                 if (rval != USB_SUCCESS) {
 471                         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
 472                             "wusb_wa_reset: can't get status, rval = %d",
 473                             rval);
 474 
 475                         return (rval);
 476                 }
 477 
 478                 if (!(status & WA_HC_RESET_IN_PROGRESS)) {
 479 
 480                         return (USB_SUCCESS);
 481                 }
 482         }
 483 
 484         return (USB_FAILURE);
 485 }
 486 
 487 /*
 488  * Enable wire adapter.
 489  *      See 8.3.1.9
 490  */
 491 int
 492 wusb_wa_enable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
 493 {
 494         dev_info_t      *dip = wa_data->wa_dip;
 495         usb_cr_t        completion_reason;
 496         usb_cb_flags_t  cb_flags;
 497         int             rval, i;
 498         uint32_t        status;
 499 
 500         if ((dip == NULL) || (ph == NULL)) {
 501 
 502                 return (USB_INVALID_ARGS);
 503         }
 504 
 505         rval = usb_pipe_sync_ctrl_xfer(dip, ph,
 506             WUSB_CLASS_IF_REQ_OUT_TYPE,
 507             USB_REQ_SET_FEATURE,
 508             WA_DEV_ENABLE,
 509             wa_data->wa_ifno,
 510             0,
 511             NULL, 0,
 512             &completion_reason, &cb_flags, 0);
 513 
 514         if (rval != USB_SUCCESS) {
 515                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
 516                     "wusb_wa_enable: can't enable WA, rval = %d, cr=%d",
 517                     rval, completion_reason);
 518 
 519                 return (rval);
 520         }
 521 
 522         for (i = 0; i < 10; i++) {
 523                 delay(drv_usectohz(50000));
 524 
 525                 rval = wusb_get_wa_status(wa_data, ph, &status);
 526                 if (rval != USB_SUCCESS) {
 527                         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
 528                             "wusb_wa_enable: can't get status, rval = %d",
 529                             rval);
 530 
 531                         return (rval);
 532                 }
 533 
 534                 if (status & WA_HC_ENABLED) {
 535 
 536                         return (USB_SUCCESS);
 537                 }
 538         }
 539 
 540         return (USB_FAILURE);
 541 }
 542 
 543 /*
 544  * Disable WA. Clear a fearture.
 545  *      See Section 8.3.1.3
 546  */
 547 int
 548 wusb_wa_disable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
 549 {
 550         dev_info_t      *dip = wa_data->wa_dip;
 551         usb_cr_t        completion_reason;
 552         usb_cb_flags_t  cb_flags;
 553         int             rval, i;
 554         uint32_t        status;
 555 
 556         if ((dip == NULL) || (ph == NULL)) {
 557 
 558                 return (USB_INVALID_ARGS);
 559         }
 560 
 561         rval = usb_pipe_sync_ctrl_xfer(dip, ph,
 562             WUSB_CLASS_IF_REQ_OUT_TYPE,
 563             USB_REQ_CLEAR_FEATURE,
 564             WA_DEV_ENABLE,
 565             wa_data->wa_ifno,
 566             0,
 567             NULL, 0,
 568             &completion_reason, &cb_flags, 0);
 569 
 570         if (rval != USB_SUCCESS) {
 571                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
 572                     "wusb_wa_disable: can't disable wa, rval = %d, cr = %d",
 573                     rval, completion_reason);
 574 
 575                 return (rval);
 576         }
 577 
 578         for (i = 0; i < 10; i++) {
 579                 delay(drv_usectohz(50000));
 580 
 581                 rval = wusb_get_wa_status(wa_data, ph, &status);
 582                 if (rval != USB_SUCCESS) {
 583                         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
 584                             "wusb_wa_disable: can't get status, rval = %d",
 585                             rval);
 586 
 587                         return (rval);
 588                 }
 589 
 590                 if (!(status & WA_HC_ENABLED)) {
 591 
 592                         return (USB_SUCCESS);
 593                 }
 594         }
 595 
 596         return (USB_FAILURE);
 597 }
 598 
 599 /*
 600  * Open the two bulk endpoints and one interrupt IN endpoint, defined in
 601  * a WA's data transfer interface. See 8.1.2
 602  */
 603 int
 604 wusb_wa_open_pipes(wusb_wa_data_t *wa_data)
 605 {
 606         int     rval;
 607 
 608         mutex_enter(&wa_data->wa_mutex);
 609         if (wa_data->wa_state & WA_PIPES_OPENED) {
 610                 mutex_exit(&wa_data->wa_mutex);
 611 
 612                 return (USB_SUCCESS);
 613         }
 614         wa_data->wa_pipe_policy.pp_max_async_reqs = 1;
 615         mutex_exit(&wa_data->wa_mutex);
 616 
 617         rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_intr_ept,
 618             &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
 619             &wa_data->wa_intr_ph);
 620         if (rval != USB_SUCCESS) {
 621                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
 622                     "wusb_wa_open_pipes: can't open intr pipe, rval = %d",
 623                     rval);
 624 
 625                 return (rval);
 626         }
 627 
 628         rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkin_ept,
 629             &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
 630             &wa_data->wa_bulkin_ph);
 631         if (rval != USB_SUCCESS) {
 632                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
 633                     "wusb_wa_open_pipes: can't open bulkin pipe, rval = %d",
 634                     rval);
 635 
 636                 usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
 637                     USB_FLAGS_SLEEP, NULL, NULL);
 638                 mutex_enter(&wa_data->wa_mutex);
 639                 wa_data->wa_intr_ph = NULL;
 640                 mutex_exit(&wa_data->wa_mutex);
 641 
 642                 return (rval);
 643         }
 644 
 645         rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkout_ept,
 646             &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
 647             &wa_data->wa_bulkout_ph);
 648 
 649         if (rval != USB_SUCCESS) {
 650                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
 651                     "wusb_wa_open_pipes: can't open bulkout pipe, rval = %d",
 652                     rval);
 653 
 654                 usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
 655                     USB_FLAGS_SLEEP, NULL, NULL);
 656                 usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph,
 657                     USB_FLAGS_SLEEP, NULL, NULL);
 658                 mutex_enter(&wa_data->wa_mutex);
 659                 wa_data->wa_intr_ph = NULL;
 660                 wa_data->wa_bulkin_ph = NULL;
 661                 mutex_exit(&wa_data->wa_mutex);
 662 
 663                 return (rval);
 664         }
 665 
 666         mutex_enter(&wa_data->wa_mutex);
 667         /* mark the state stopped until listening is started on the pipes */
 668         wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED;
 669         wa_data->wa_bulkin_pipe_state = WA_PIPE_STOPPED;
 670         /* no listening on this pipe, just mark it active */
 671         wa_data->wa_bulkout_pipe_state = WA_PIPE_ACTIVE;
 672         wa_data->wa_state |= WA_PIPES_OPENED;
 673         mutex_exit(&wa_data->wa_mutex);
 674 
 675         return (USB_SUCCESS);
 676 }
 677 
 678 /*
 679  * Close WA's pipes.
 680  */
 681 void
 682 wusb_wa_close_pipes(wusb_wa_data_t *wa_data)
 683 {
 684         mutex_enter(&wa_data->wa_mutex);
 685         if ((wa_data->wa_state & WA_PIPES_OPENED) == 0) {
 686                 mutex_exit(&wa_data->wa_mutex);
 687 
 688                 return;
 689         }
 690 
 691         mutex_exit(&wa_data->wa_mutex);
 692 
 693         usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
 694             USB_FLAGS_SLEEP, NULL, NULL);
 695 
 696         if (wa_data->wa_bulkin_ph != NULL) {
 697                 usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph,
 698                     USB_FLAGS_SLEEP, NULL, NULL);
 699         }
 700 
 701         usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkout_ph,
 702             USB_FLAGS_SLEEP, NULL, NULL);
 703 
 704         mutex_enter(&wa_data->wa_mutex);
 705         wa_data->wa_intr_ph = NULL;
 706         wa_data->wa_bulkin_ph = NULL;
 707         wa_data->wa_bulkout_ph = NULL;
 708         wa_data->wa_intr_pipe_state = WA_PIPE_CLOSED;
 709         wa_data->wa_bulkin_pipe_state = WA_PIPE_CLOSED;
 710         wa_data->wa_bulkout_pipe_state = WA_PIPE_CLOSED;
 711         wa_data->wa_state &= ~WA_PIPES_OPENED;
 712         mutex_exit(&wa_data->wa_mutex);
 713 }
 714 
 715 /*
 716  * start listening for transfer completion notifications or device
 717  * notifications on the notification ept
 718  */
 719 int
 720 wusb_wa_start_nep(wusb_wa_data_t *wa_data, usb_flags_t flag)
 721 {
 722         int             rval;
 723         usb_intr_req_t  *reqp;
 724 
 725         mutex_enter(&wa_data->wa_mutex);
 726         if ((wa_data->wa_intr_ph == NULL) ||
 727             (wa_data->wa_intr_pipe_state != WA_PIPE_STOPPED)) {
 728                 mutex_exit(&wa_data->wa_mutex);
 729 
 730                 return (USB_INVALID_PIPE);
 731         }
 732 
 733         reqp = usb_alloc_intr_req(wa_data->wa_dip, 0, flag);
 734         if (!reqp) {
 735                 mutex_exit(&wa_data->wa_mutex);
 736 
 737                 return (USB_NO_RESOURCES);
 738         }
 739 
 740         reqp->intr_client_private = (usb_opaque_t)wa_data;
 741         reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
 742             USB_ATTRS_AUTOCLEARING;
 743         reqp->intr_len = wa_data->wa_intr_ept.wMaxPacketSize;
 744         reqp->intr_cb = wa_data->intr_cb;
 745         reqp->intr_exc_cb = wa_data->intr_exc_cb;
 746         mutex_exit(&wa_data->wa_mutex);
 747 
 748         if ((rval = usb_pipe_intr_xfer(wa_data->wa_intr_ph, reqp,
 749             flag)) != USB_SUCCESS) {
 750                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
 751                     "wusb_wa_start_nep: intr xfer fail, rval = %d",
 752                     rval);
 753 
 754                 usb_free_intr_req(reqp);
 755 
 756                 return (rval);
 757         }
 758 
 759         mutex_enter(&wa_data->wa_mutex);
 760         /* pipe state is active while the listening is on */
 761         wa_data->wa_intr_pipe_state = WA_PIPE_ACTIVE;
 762         mutex_exit(&wa_data->wa_mutex);
 763 
 764         return (USB_SUCCESS);
 765 }
 766 
 767 /*
 768  * stop the notification ept from listening
 769  */
 770 void
 771 wusb_wa_stop_nep(wusb_wa_data_t *wa_data)
 772 {
 773         mutex_enter(&wa_data->wa_mutex);
 774         if ((wa_data->wa_intr_ph == NULL) ||
 775             (wa_data->wa_intr_pipe_state != WA_PIPE_ACTIVE)) {
 776                 mutex_exit(&wa_data->wa_mutex);
 777 
 778                 return;
 779         }
 780         wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED;
 781         mutex_exit(&wa_data->wa_mutex);
 782         /* stop intr in without closing the pipe */
 783         usb_pipe_stop_intr_polling(wa_data->wa_intr_ph, USB_FLAGS_SLEEP);
 784 }
 785 
 786 /*
 787  * allocate a rpipe for transfers on a pipe
 788  *      - Find a free RPipe
 789  *
 790  * For now, one rpipe is associated with only one usba pipe once
 791  * the pipe is opened. In the future, the rpipe needs to be
 792  * multiplexed between asynchronous endpoints
 793  * input:
 794  *      type: 0 - ctrl, 1 - isoc, 2 - bulk, 3 - intr
 795  *
 796  */
 797 /* ARGSUSED */
 798 int
 799 wusb_wa_get_rpipe(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
 800         uint8_t type, wusb_wa_rpipe_hdl_t **hdl,
 801         uint_t mask, usb_log_handle_t handle)
 802 {
 803         int                     i;
 804         wusb_wa_rpipe_hdl_t     *thdl;
 805         uint8_t                 rp_type;
 806         uint8_t                 ep_type = 1 << type;
 807 
 808         *hdl = NULL;
 809 
 810         mutex_enter(&wa_data->wa_mutex);
 811         for (i = 0; i < wa_data->wa_num_rpipes; i++) {
 812                 /* find the first unused rpipe */
 813                 thdl = &wa_data->wa_rpipe_hdl[i];
 814                 mutex_enter(&thdl->rp_mutex);
 815                 if (thdl->rp_state != WA_RPIPE_STATE_FREE) {
 816                         mutex_exit(&thdl->rp_mutex);
 817 
 818                         continue;
 819                 }
 820 
 821                 /* check if the rpipe supports the ept transfer type */
 822                 rp_type = (thdl->rp_descr.bmCharacteristics &
 823                     USB_RPIPE_CHA_MASK);
 824                 if (rp_type & ep_type) {
 825                         thdl->rp_refcnt++;
 826                         thdl->rp_state = WA_RPIPE_STATE_IDLE;
 827                         thdl->rp_avail_reqs = thdl->rp_descr.wRequests;
 828                         *hdl = thdl;
 829                         mutex_exit(&thdl->rp_mutex);
 830                         mutex_exit(&wa_data->wa_mutex);
 831 
 832                         return (USB_SUCCESS);
 833                 }
 834                 mutex_exit(&thdl->rp_mutex);
 835         }
 836 
 837         USB_DPRINTF_L2(mask, handle,
 838             "wusb_wa_get_rpipe: no matching rpipe is found");
 839         mutex_exit(&wa_data->wa_mutex);
 840 
 841         return (USB_FAILURE);
 842 }
 843 
 844 /*
 845  * Decrease a RPipe's reference count.
 846  *      - if count == 0, mark it as free RPipe.
 847  */
 848 int
 849 wusb_wa_release_rpipe(wusb_wa_data_t *wa, wusb_wa_rpipe_hdl_t *hdl)
 850 {
 851         if (hdl == NULL) {
 852 
 853                 return (USB_FAILURE);
 854         }
 855 
 856         mutex_enter(&wa->wa_mutex);
 857         mutex_enter(&hdl->rp_mutex);
 858         if (hdl->rp_refcnt == 0) {
 859                 mutex_exit(&hdl->rp_mutex);
 860                 mutex_exit(&wa->wa_mutex);
 861 
 862                 return (USB_FAILURE);
 863         }
 864 
 865         if (--hdl->rp_refcnt == 0) {
 866                 hdl->rp_state = WA_RPIPE_STATE_FREE;
 867         }
 868 
 869         if (hdl->rp_block_chg == 1) {
 870                 wa->wa_avail_blocks += hdl->rp_descr.wBlocks;
 871                 hdl->rp_descr.wBlocks = 0; /* to prevent misadd upon re-call */
 872                 hdl->rp_block_chg = 0;
 873         }
 874 
 875         mutex_exit(&hdl->rp_mutex);
 876         mutex_exit(&wa->wa_mutex);
 877 
 878         return (USB_SUCCESS);
 879 }
 880 
 881 /*
 882  * Set a RPipe's Descriptor and make the rpipe configured
 883  *      See section 8.3.1.7
 884  */
 885 int
 886 wusb_wa_set_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph,
 887         usb_wa_rpipe_descr_t *rp_descr)
 888 {
 889         mblk_t          *data = NULL;
 890         usb_cr_t        completion_reason;
 891         usb_cb_flags_t  cb_flags;
 892         int             rval;
 893         uint8_t         *p;
 894 
 895         data = allocb_wait(USB_RPIPE_DESCR_SIZE, BPRI_LO, STR_NOSIG, NULL);
 896         p = data->b_wptr;
 897         p[0] = rp_descr->bLength;
 898         p[1] = rp_descr->bDescriptorType;
 899         p[2] = rp_descr->wRPipeIndex;
 900         p[3] = rp_descr->wRPipeIndex >> 8;
 901         p[4] = rp_descr->wRequests;
 902         p[5] = rp_descr->wRequests >> 8;
 903         p[6] = rp_descr->wBlocks;
 904         p[7] = rp_descr->wBlocks >> 8;
 905         p[8] = rp_descr->wMaxPacketSize;
 906         p[9] = rp_descr->wMaxPacketSize >> 8;
 907         p[10] = rp_descr->wa_value.hwa_value.bMaxBurst;
 908         p[11] = rp_descr->wa_value.hwa_value.bDeviceInfoIndex;
 909         p[12] = rp_descr->bSpeed;
 910         p[13] = rp_descr->bDeviceAddress;
 911         p[14] = rp_descr->bEndpointAddress;
 912         p[15] = rp_descr->bDataSequence;
 913         p[16] = rp_descr->dwCurrentWindow;
 914         p[17] = rp_descr->dwCurrentWindow >> 8;
 915         p[18] = rp_descr->dwCurrentWindow >> 16;
 916         p[19] = rp_descr->dwCurrentWindow >> 24;
 917         p[20] = rp_descr->bMaxDataSequence;
 918         p[21] = rp_descr->bInterval;
 919         p[22] = rp_descr->bOverTheAirInterval;
 920         p[23] = rp_descr->bmAttribute;
 921         p[24] = rp_descr->bmCharacteristics;
 922         p[25] = rp_descr->bmRetryOptions;
 923         p[26] = rp_descr->wNumTransactionErrors;
 924         p[27] = rp_descr->wNumTransactionErrors >> 8;
 925 
 926         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
 927             "wusb_wa_set_rpipe_descr: RPipe Descriptors");
 928         wusb_wa_dump_rpipe_descr(rp_descr, DPRINT_MASK_WHCDI, whcdi_log_handle);
 929 
 930         rval = usb_pipe_sync_ctrl_xfer(dip, ph,
 931             WA_CLASS_RPIPE_REQ_OUT_TYPE,
 932             USB_REQ_SET_DESCR,
 933             USB_DESCR_TYPE_RPIPE << 8,
 934             rp_descr->wRPipeIndex,
 935             USB_RPIPE_DESCR_SIZE,
 936             &data, 0,
 937             &completion_reason, &cb_flags, 0);
 938 
 939         freemsg(data);
 940 
 941         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
 942             "wusb_wa_set_rpipe_descr: rval = %d", rval);
 943 
 944         return (rval);
 945 }
 946 
 947 /* ept companion descr for the default ctrl pipe, refer to WUSB 1.0/4.8.1 */
 948 usb_ep_comp_descr_t ep_comp0 = {
 949         sizeof (usb_ep_comp_descr_t), USB_DESCR_TYPE_WIRELESS_EP_COMP,
 950         1, 2,
 951 };
 952 
 953 /*
 954  * Get the Endpoint Companion Descriptor for the pipe
 955  *      ph_data - the specified pipe
 956  *      ep_comp - the companion descriptor returned
 957  */
 958 int
 959 wusb_wa_get_ep_comp_descr(usba_pipe_handle_data_t *ph_data,
 960         usb_ep_comp_descr_t *ep_comp)
 961 {
 962         usb_ep_descr_t          *ep = &ph_data->p_ep;
 963         usb_client_dev_data_t   *dev_data;
 964         usb_if_data_t           *if_data;
 965         usb_alt_if_data_t       *altif_data;
 966         usb_ep_data_t           *ep_data;
 967         int                     i, j;
 968 
 969         /* default ctrl endpoint */
 970         if (ep->bEndpointAddress == 0) {
 971                 *ep_comp = ep_comp0;
 972 
 973                 return (USB_SUCCESS);
 974         }
 975 
 976         if (usb_get_dev_data(ph_data->p_dip, &dev_data,
 977             USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
 978 
 979                 return (USB_FAILURE);
 980         }
 981 
 982         /* retrieve ept companion descr from the dev data */
 983         if_data = &dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if];
 984         for (i = 0; i < if_data->if_n_alt; i++) {
 985                 altif_data = &if_data->if_alt[i];
 986                 for (j = 0; j < altif_data->altif_n_ep; j++) {
 987                         ep_data = &altif_data->altif_ep[j];
 988                         if (memcmp(&ep_data->ep_descr, ep,
 989                             sizeof (usb_ep_descr_t)) == 0) {
 990                                 *ep_comp = ep_data->ep_comp_descr;
 991                                 usb_free_dev_data(ph_data->p_dip, dev_data);
 992 
 993                                 return (USB_SUCCESS);
 994                         }
 995                 }
 996         }
 997         usb_free_dev_data(ph_data->p_dip, dev_data);
 998 
 999         return (USB_FAILURE);
1000 }
1001 
1002 /* to check if the specified PHY speed is supported by the device */
1003 int
1004 wusb_wa_is_speed_valid(usba_device_t *ud, uint8_t speed)
1005 {
1006         usb_uwb_cap_descr_t *uwb_descr = ud->usb_wireless_data->uwb_descr;
1007         uint8_t valid_spd[WUSB_PHY_TX_RATE_RES] = {
1008             WUSB_DATA_RATE_BIT_53, WUSB_DATA_RATE_BIT_106,
1009             WUSB_DATA_RATE_BIT_160, WUSB_DATA_RATE_BIT_200,
1010             WUSB_DATA_RATE_BIT_320, WUSB_DATA_RATE_BIT_400,
1011             WUSB_DATA_RATE_BIT_480, 0
1012         };
1013 
1014         if (speed >= WUSB_PHY_TX_RATE_RES) {
1015 
1016                 return (0);
1017         }
1018 
1019         /* this speed is not supported by the device */
1020         if (valid_spd[speed] != (uwb_descr->wPHYRates & valid_spd[speed])) {
1021 
1022                 return (0);
1023         }
1024 
1025         return (1);
1026 }
1027 
1028 /*
1029  * Set up a RPipe
1030  *      - Associate a RPipe and a pipe handle. Hence, an endpoint has
1031  *        RPipe to transfer data.
1032  *      - Set this RPipe to bDeviceAddress:bEndpointAddress
1033  *
1034  *  wa  - wa data
1035  *  ph  - wa's default control pipe
1036  *  ph_data - client driver's usba pipe to be opened
1037  *  hdl - RPipe handle
1038  */
1039 int
1040 wusb_wa_set_rpipe_target(dev_info_t *dip, wusb_wa_data_t *wa,
1041         usb_pipe_handle_t ph, usba_pipe_handle_data_t *ph_data,
1042         wusb_wa_rpipe_hdl_t *hdl)
1043 {
1044         int                     rval;
1045         usb_ep_comp_descr_t     ep_comp;
1046         usb_ep_descr_t          *ep = &ph_data->p_ep;
1047         usba_device_t           *usba_device;
1048         uint8_t                 rp_status;
1049         usb_wa_descr_t          *wa_desc = &wa->wa_descr;
1050         uint16_t                blockcnt;
1051         uint16_t                maxsize;
1052         uint16_t                seg_len;
1053 
1054 
1055         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1056             "wusb_wa_set_rpipe_target: ph_data = 0x%p rp_hdl = 0x%p",
1057             (void*)ph_data, (void*)hdl);
1058 
1059         /* Get client device's Endpoint companion descriptor */
1060         if ((rval = wusb_wa_get_ep_comp_descr(ph_data, &ep_comp)) !=
1061             USB_SUCCESS) {
1062                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1063                     "wusb_wa_set_rpipe_target: get companion ep descr failed,"
1064                     " rval = %d", rval);
1065 
1066                 return (rval);
1067         }
1068 
1069         /* set the rpipe to unconfigured state */
1070         if ((rval = wusb_wa_rpipe_reset(dip, ph_data, hdl, 0)) != USB_SUCCESS) {
1071                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1072                     "wusb_wa_set_rpipe_target: reset rpipe failed, rval = %d",
1073                     rval);
1074 
1075                 return (rval);
1076         }
1077 
1078         if ((rval = wusb_wa_get_rpipe_status(dip, ph,
1079             hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) {
1080                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1081                     "wusb_wa_set_rpipe_target: get rpipe status failed, "
1082                     "rval = %d", rval);
1083 
1084                 return (rval);
1085         }
1086 
1087         if (rp_status & WA_RPIPE_CONFIGURED) {
1088                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1089                     "wusb_wa_set_rpipe_target: reset rpipe unsuccessful");
1090 
1091                 return (USB_FAILURE);
1092         }
1093 
1094         mutex_enter(&wa->wa_mutex);
1095         usba_device = usba_get_usba_device(ph_data->p_dip);
1096 
1097         mutex_enter(&hdl->rp_mutex);
1098 
1099         /* should be 0x200 for default ctrl pipe, refer to wusb 1.0/4.8.1 */
1100         hdl->rp_descr.wMaxPacketSize = ep->wMaxPacketSize;
1101 
1102         /*
1103          * set rpipe descr values
1104          *
1105          * Try to use an average block value first. If it's too small,
1106          * then try to allocate the minimum block size to accomodate one
1107          * packet. If the required number of block is not available, return
1108          * failure.
1109          */
1110         if (hdl->rp_descr.wBlocks == 0) {
1111                 blockcnt = wa_desc->wRPipeMaxBlock/wa_desc->wNumRPipes;
1112                 maxsize = 1 << (wa_desc->bRPipeBlockSize - 1);
1113                 seg_len = blockcnt * maxsize;
1114 
1115                 /* alloc enough blocks to accomodate one packet */
1116                 if (ep->wMaxPacketSize > seg_len) {
1117                         blockcnt = (ep->wMaxPacketSize + maxsize -1)/maxsize;
1118                 }
1119 
1120                 /* WA don't have so many blocks to fulfill this reqirement */
1121                 if (wa->wa_avail_blocks < blockcnt) {
1122                         mutex_exit(&hdl->rp_mutex);
1123                         mutex_exit(&wa->wa_mutex);
1124 
1125                         return (USB_FAILURE);
1126                 }
1127 
1128                 /* we're satisfied */
1129                 hdl->rp_descr.wBlocks = blockcnt;
1130                 hdl->rp_block_chg = 1; /* the wBlocks is changed */
1131                 wa->wa_avail_blocks -= blockcnt;
1132         }
1133         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1134             "wusb_wa_set_rpipe_target: wBlocks=%d, maxblock=%d, numR=%d, av=%d",
1135             hdl->rp_descr.wBlocks, wa_desc->wRPipeMaxBlock, wa_desc->wNumRPipes,
1136             wa->wa_avail_blocks);
1137 
1138         hdl->rp_descr.wa_value.hwa_value.bMaxBurst = ep_comp.bMaxBurst;
1139 
1140         /*
1141          * DEVICE INDEX
1142          * device info index should be zero based, refer
1143          * to WUSB 1.0/8.5.3.7
1144          */
1145         hdl->rp_descr.wa_value.hwa_value.bDeviceInfoIndex =
1146             usba_device->usb_port - 1;
1147 
1148         /*
1149          * default ctrl pipe uses PHY base signaling rate
1150          * refer to wusb 1.0/4.8.1
1151          */
1152         if (ep->bEndpointAddress == 0) {
1153                 hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_53;
1154         } else {
1155                 if (wusb_wa_is_speed_valid(usba_device, rp_default_speed)) {
1156                         hdl->rp_descr.bSpeed = rp_default_speed;
1157                 } else {
1158                         /* use a must-supported speed */
1159                         hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_106;
1160                 }
1161         }
1162         hdl->rp_descr.bDeviceAddress = usba_device->usb_addr;
1163         hdl->rp_descr.bEndpointAddress = ep->bEndpointAddress;
1164         hdl->rp_descr.bDataSequence = 0;
1165         hdl->rp_descr.dwCurrentWindow = 1;
1166         hdl->rp_descr.bMaxDataSequence = ep_comp.bMaxSequence - 1;
1167         hdl->rp_descr.bInterval = ep->bInterval;
1168         hdl->rp_descr.bOverTheAirInterval = ep_comp.bOverTheAirInterval;
1169         hdl->rp_descr.bmAttribute = ep->bmAttributes & 0x03;
1170         hdl->rp_descr.bmRetryOptions = 0; /* keep retrying */
1171         hdl->rp_descr.wNumTransactionErrors = 0;
1172         mutex_exit(&hdl->rp_mutex);
1173 
1174         mutex_exit(&wa->wa_mutex);
1175 
1176         /* set rpipe descr */
1177         rval = wusb_wa_set_rpipe_descr(dip, ph, &hdl->rp_descr);
1178         if (rval != USB_SUCCESS) {
1179                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1180                     "wusb_wa_set_rpipe_target: set rpipe descr failed, "
1181                     "rval = %d", rval);
1182 
1183                 return (rval);
1184         }
1185 
1186         /* check rpipe status, must be configured and idle */
1187         if ((rval = wusb_wa_get_rpipe_status(dip, ph,
1188             hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) {
1189                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1190                     "wusb_wa_set_rpipe_target: get rpipe status failed, "
1191                     "rval = %d", rval);
1192 
1193                 return (rval);
1194         }
1195 
1196         if (rp_status != (WA_RPIPE_CONFIGURED | WA_RPIPE_IDLE)) {
1197                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1198                     "wusb_wa_set_rpipe_target: set rpipe descr unsuccessful");
1199 
1200                 return (USB_FAILURE);
1201         }
1202 
1203         return (rval);
1204 }
1205 
1206 /*
1207  * Abort a RPipe
1208  *      - See Section 8.3.1.1
1209  *      - Aborts all transfers pending on the given pipe
1210  */
1211 int
1212 wusb_wa_rpipe_abort(dev_info_t *dip, usb_pipe_handle_t ph,
1213         wusb_wa_rpipe_hdl_t *hdl)
1214 {
1215         usb_cr_t        completion_reason;
1216         usb_cb_flags_t  cb_flags;
1217         int             rval;
1218 
1219         mutex_enter(&hdl->rp_mutex);
1220 
1221         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1222             "wusb_wa_rpipe_abort: rp_hdl = 0x%p", (void *)hdl);
1223 
1224         /* only abort when there is active transfer */
1225         if (hdl->rp_state != WA_RPIPE_STATE_ACTIVE) {
1226                 mutex_exit(&hdl->rp_mutex);
1227 
1228                 return (USB_SUCCESS);
1229         }
1230 
1231         mutex_exit(&hdl->rp_mutex);
1232         rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1233             WA_CLASS_RPIPE_REQ_OUT_TYPE,
1234             WA_REQ_ABORT_RPIPE,
1235             0,
1236             hdl->rp_descr.wRPipeIndex,
1237             0,
1238             NULL, 0,
1239             &completion_reason, &cb_flags, 0);
1240 
1241         if (rval != USB_SUCCESS) {
1242                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1243                     "wusb_wa_rpipe_abort: abort failed, rval = %d", rval);
1244 
1245                 return (rval);
1246         }
1247 
1248         return (USB_SUCCESS);
1249 }
1250 
1251 /*
1252  * Clear status on the remote device's endpoint, specifically clear the
1253  * RPipe's target endpoint sequence number. See 4.5.3, 4.6.4 and Tab.8-49
1254  * for reference of data sequence.
1255  *
1256  * NOTE AGAIN:
1257  * The device endpoint will not respond to host request if the RPipe is
1258  * reset or re-targeted, while device endpoint is not reset!
1259  */
1260 void
1261 wusb_wa_clear_dev_ep(usba_pipe_handle_data_t *ph)
1262 {
1263         uint8_t ept_addr;
1264 
1265         if (ph == NULL) {
1266                 return;
1267         }
1268 
1269         ept_addr = ph->p_ep.bEndpointAddress;
1270 
1271         USB_DPRINTF_L4(PRINT_MASK_HCDI, whcdi_log_handle,
1272             "wusb_wa_clear_dev_ep:clear endpoint = 0x%02x", ept_addr);
1273         if (ept_addr != 0) {
1274         /* only clear non-default endpoints */
1275                 (void) usb_clr_feature(ph->p_dip, USB_DEV_REQ_RCPT_EP, 0,
1276                     ept_addr, USB_FLAGS_SLEEP, NULL, NULL);
1277         }
1278 }
1279 
1280 /*
1281  * Reset a RPipe
1282  *      - Reset a RPipe to a known state
1283  *      - Pending transfers must be drained or aborted before this
1284  *        operation.
1285  *      - See Section 8.3.1.10
1286  *
1287  *  dip - the WA's devinfo
1288  *  ph  - RPipe's targeted remote device's endpoint pipe.
1289  *  hdl - RPipe's handle
1290  *
1291  *  flag = 1, reset the RPipe descriptor to its initial state and
1292  *         also clear remote device endpoint
1293  *       = 0, not reset the RPipe descriptor. Caller should use 0 flag
1294  *        if it's the first time to open a pipe, because we don't have
1295  *        a valid ph yet before successfully opening a pipe by using
1296  *        usb_pipe_open().
1297  */
1298 int
1299 wusb_wa_rpipe_reset(dev_info_t *dip, usba_pipe_handle_data_t *ph,
1300     wusb_wa_rpipe_hdl_t *hdl, int flag)
1301 {
1302         int             rval = 0;
1303         usb_cr_t        completion_reason;
1304         usb_cb_flags_t  cb_flags = 0;
1305         usb_pipe_handle_t       default_ph;
1306 
1307         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1308             "wusb_wa_rpipe_reset: rp_hdl = 0x%p, ep=0x%02x, flag = %d",
1309             (void *)hdl, ph->p_ep.bEndpointAddress, flag);
1310 
1311         /* get WA's default pipe */
1312         default_ph = usba_get_dflt_pipe_handle(dip);
1313 
1314         rval = usb_pipe_sync_ctrl_xfer(dip, default_ph,
1315             WA_CLASS_RPIPE_REQ_OUT_TYPE,
1316             WA_REQ_RESET_RPIPE,
1317             0,
1318             hdl->rp_descr.wRPipeIndex,
1319             0,
1320             NULL, 0,
1321             &completion_reason, &cb_flags, 0);
1322 
1323         if (rval != USB_SUCCESS) {
1324                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1325                     "wusb_wa_rpipe_reset: reset failed, rval=%d"
1326                     " cr=%d cb=0x%02x",
1327                     rval, (int)completion_reason, (int)cb_flags);
1328 
1329                 return (rval);
1330         }
1331 
1332         if (flag == 0) {
1333                 /* do nothing else, just return, the rpipe is unconfigured */
1334                 return (USB_SUCCESS);
1335         }
1336 
1337         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1338             "wusb_wa_rpipe_reset: need to clear dev pipe and reset RP descr");
1339 
1340         /* set rpipe descr and make the rpipe configured */
1341         rval = wusb_wa_set_rpipe_descr(dip, default_ph, &hdl->rp_descr);
1342         if (rval != USB_SUCCESS) {
1343                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1344                     "wusb_wa_rpipe_reset: set descr failed, rval = %d", rval);
1345 
1346                 return (rval);
1347         }
1348 
1349         mutex_enter(&hdl->rp_mutex);
1350         hdl->rp_avail_reqs = hdl->rp_descr.wRequests;
1351         if (hdl->rp_state == WA_RPIPE_STATE_ERROR) {
1352                 hdl->rp_state = WA_RPIPE_STATE_IDLE;
1353         }
1354         mutex_exit(&hdl->rp_mutex);
1355 
1356         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1357             "wusb_wa_rpipe_reset: end");
1358 
1359         return (USB_SUCCESS);
1360 }
1361 
1362 /* get rpipe status, refer to WUSB 1.0/8.3.1.5 */
1363 int
1364 wusb_wa_get_rpipe_status(dev_info_t *dip, usb_pipe_handle_t ph, uint16_t idx,
1365         uint8_t *status)
1366 {
1367         mblk_t          *data = NULL;
1368         usb_cr_t        completion_reason;
1369         usb_cb_flags_t  cb_flags;
1370         int             rval;
1371 
1372         rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1373             WA_CLASS_RPIPE_REQ_IN_TYPE,
1374             USB_REQ_GET_STATUS,
1375             0,
1376             idx,
1377             1,
1378             &data, 0,
1379             &completion_reason, &cb_flags, 0);
1380 
1381         if (rval != USB_SUCCESS) {
1382                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1383                     "wusb_wa_get_rpipe_status: fail, rval=%d, cr=%d, "
1384                     "cb=0x%x", rval, completion_reason, cb_flags);
1385         } else {
1386                 *status = *data->b_rptr;
1387                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1388                     "wusb_wa_get_rpipe_status: status = %x", *status);
1389                 freemsg(data);
1390         }
1391 
1392         return (rval);
1393 }
1394 
1395 /*
1396  * WA specific operations end
1397  */
1398 
1399 /* Transfer related routines */
1400 wusb_wa_trans_wrapper_t *
1401 wusb_wa_alloc_tw(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1402         usba_pipe_handle_data_t *ph, uint32_t datalen, usb_flags_t usb_flags)
1403 {
1404         uint_t                  seg_count;
1405         uint32_t                seg_len, maxpktsize;
1406         wusb_wa_trans_wrapper_t *wr;
1407 
1408         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1409             "wusb_wa_alloc_tw: ph = 0x%p rp_hdl = 0x%p ",
1410             (void*)ph, (void*)hdl);
1411 
1412         mutex_enter(&hdl->rp_mutex);
1413 
1414         /* compute the rpipe buffer size */
1415         seg_len = hdl->rp_descr.wBlocks *
1416             (1 << (wa_data->wa_descr.bRPipeBlockSize - 1));
1417         maxpktsize = hdl->rp_descr.wMaxPacketSize;
1418         mutex_exit(&hdl->rp_mutex);
1419 
1420         if (seg_len < maxpktsize) {
1421                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1422                     "wusb_wa_alloc_tw: fail, segment len(%d) "
1423                     "< wMaxPacketSize(%d) ", seg_len, maxpktsize);
1424 
1425                 return (NULL);
1426         }
1427 
1428         /*
1429          * the transfer length for each segment is a multiple of the
1430          * wMaxPacketSize except the last segment, and the length
1431          * cannot exceed the rpipe buffer size
1432          */
1433         seg_len = (seg_len / maxpktsize) * maxpktsize;
1434         if (datalen) {
1435                 seg_count = (datalen + seg_len - 1) / seg_len;
1436         } else {
1437                 seg_count = 1;
1438         }
1439 
1440         if (seg_count > WA_MAX_SEG_COUNT) {
1441                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1442                     "wusb_wa_alloc_tw: fail, seg count(%d)"
1443                     " > Max allowed number(%d) ", seg_count, WA_MAX_SEG_COUNT);
1444 
1445                 return (NULL);
1446         }
1447 
1448         if ((wr = kmem_zalloc(sizeof (wusb_wa_trans_wrapper_t),
1449             KM_NOSLEEP)) == NULL) {
1450 
1451                 return (NULL);
1452         }
1453 
1454         /* allocation, not visible to other threads */
1455         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1456 
1457         if ((wr->wr_seg_array = kmem_zalloc(sizeof (wusb_wa_seg_t) * seg_count,
1458             KM_NOSLEEP)) == NULL) {
1459                 kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
1460 
1461                 return (NULL);
1462         }
1463 
1464         /* assign a unique ID for each transfer */
1465         wr->wr_id = WA_GET_ID(wr);
1466         if (wr->wr_id == 0) {
1467                 kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) *
1468                     seg_count);
1469                 kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
1470 
1471                 return (NULL);
1472         }
1473 
1474         wr->wr_ph = ph;
1475         wr->wr_rp = hdl;
1476         wr->wr_wa_data = wa_data;
1477         wr->wr_flags = usb_flags;
1478         wr->wr_nsegs = (uint8_t)seg_count;
1479         wr->wr_max_seglen = seg_len;
1480         wr->wr_has_aborted = 0;
1481 
1482         cv_init(&wr->wr_cv, NULL, CV_DRIVER, NULL);
1483 
1484         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1485             "wusb_wa_alloc_tw: wr = 0x%p id = %x nseg = %d", (void*)wr,
1486             wr->wr_id, wr->wr_nsegs);
1487 
1488         return (wr);
1489 }
1490 
1491 /* create transfer wrapper for a ctrl request, return NULL on failure */
1492 wusb_wa_trans_wrapper_t *
1493 wusb_wa_create_ctrl_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1494         usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
1495         usb_flags_t usb_flags)
1496 {
1497         wusb_wa_trans_wrapper_t *wr = NULL;
1498 
1499         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1500             "wusb_wa_create_ctrl_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
1501             (void *)ph, (void*)hdl, (void *)ctrl_reqp);
1502 
1503         wr = wusb_wa_alloc_tw(wa_data, hdl, ph, ctrl_reqp->ctrl_wLength,
1504             usb_flags);
1505         if (wr == NULL) {
1506                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1507                     "wusb_wa_create_ctrl_wrapper: fail to create tw for %p",
1508                     (void *)ctrl_reqp);
1509 
1510                 return (NULL);
1511         }
1512 
1513         /* not visible to other threads yet */
1514         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1515 
1516         if (ctrl_reqp->ctrl_bmRequestType & USB_DEV_REQ_DEV_TO_HOST) {
1517                 wr->wr_dir = WA_DIR_IN;
1518         } else {
1519                 wr->wr_dir = WA_DIR_OUT;
1520         }
1521 
1522         wr->wr_type = WA_XFER_REQ_TYPE_CTRL;
1523         wr->wr_reqp = (usb_opaque_t)ctrl_reqp;
1524         wr->wr_timeout = (ctrl_reqp->ctrl_timeout == 0) ?
1525             WA_RPIPE_DEFAULT_TIMEOUT : ctrl_reqp->ctrl_timeout;
1526         wr->wr_cb = wusb_wa_handle_ctrl;
1527 
1528         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1529             "wusb_wa_create_ctrl_wrapper: wr = 0x%p nseg = %d", (void *)wr,
1530             wr->wr_nsegs);
1531 
1532         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1533 
1534         return (wr);
1535 }
1536 
1537 /*
1538  * create transfer wrapper for a bulk request, return NULL on failure
1539  *      - split the request into multiple segments
1540  *      - every segment is N * wMaxPacketSize
1541  *      - segment length <= bRPipeBlockSize * wBlocks
1542  */
1543 wusb_wa_trans_wrapper_t *
1544 wusb_wa_create_bulk_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1545         usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
1546         usb_flags_t usb_flags)
1547 {
1548         wusb_wa_trans_wrapper_t *wr = NULL;
1549         usb_ep_descr_t          *epdt = &ph->p_ep;
1550 
1551         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1552             "wusb_wa_create_bulk_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
1553             (void *)ph, (void *)hdl, (void *)bulk_reqp);
1554 
1555         wr = wusb_wa_alloc_tw(wa_data, hdl, ph, bulk_reqp->bulk_len,
1556             usb_flags);
1557         if (wr == NULL) {
1558                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1559                     "wusb_wa_create_bulk_wrapper: fail to create tw for %p",
1560                     (void *)bulk_reqp);
1561 
1562                 return (NULL);
1563         }
1564 
1565         /* no locking needed */
1566         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1567 
1568         if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1569                 wr->wr_dir = WA_DIR_IN;
1570         } else {
1571                 wr->wr_dir = WA_DIR_OUT;
1572         }
1573 
1574         wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR;
1575         wr->wr_reqp = (usb_opaque_t)bulk_reqp;
1576         wr->wr_timeout = (bulk_reqp->bulk_timeout == 0) ?
1577             WA_RPIPE_DEFAULT_TIMEOUT : bulk_reqp->bulk_timeout;
1578         wr->wr_cb = wusb_wa_handle_bulk;
1579 
1580         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1581             "wusb_wa_create_bulk_wrapper: wr = 0x%p nseg = %d", (void *)wr,
1582             wr->wr_nsegs);
1583 
1584         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1585 
1586         return (wr);
1587 }
1588 
1589 /*
1590  * create transfer wrapper for a intr request, return NULL on failure
1591  *      - split the request into multiple segments
1592  *      - every segment is N * wMaxPacketSize
1593  *      - segment length <= bRPipeBlockSize * wBlocks
1594  */
1595 wusb_wa_trans_wrapper_t *
1596 wusb_wa_create_intr_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1597         usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
1598         usb_flags_t usb_flags)
1599 {
1600         wusb_wa_trans_wrapper_t *wr;
1601         usb_ep_descr_t          *epdt = &ph->p_ep;
1602         uint32_t                tw_len;
1603         usb_intr_req_t *curr_intr_reqp;
1604 
1605         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1606             "wusb_wa_create_intr_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
1607             (void *)ph, (void *)hdl, (void *)intr_reqp);
1608 
1609         if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1610                 tw_len = (intr_reqp->intr_len) ? intr_reqp->intr_len :
1611                     ph->p_ep.wMaxPacketSize;
1612 
1613                 /* duplicate client's intr request */
1614                 curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
1615                     (usb_intr_req_t *)intr_reqp, tw_len, usb_flags);
1616                 if (curr_intr_reqp == NULL) {
1617                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1618                             "wusb_wa_create_intr_wrapper: fail to create reqp");
1619 
1620                         return (NULL);
1621                 }
1622 
1623         } else { /* OUT */
1624                 tw_len = intr_reqp->intr_len;
1625                 curr_intr_reqp = intr_reqp;
1626         }
1627 
1628         wr = wusb_wa_alloc_tw(wa_data, hdl, ph, tw_len, usb_flags);
1629         if (wr == NULL) {
1630                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1631                     "wusb_wa_create_bulk_wrapper: fail to create tw for %p",
1632                     (void *)intr_reqp);
1633 
1634                 return (NULL);
1635         }
1636 
1637         /* no locking needed */
1638         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1639 
1640         if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1641                 wr->wr_dir = WA_DIR_IN;
1642         } else {
1643                 wr->wr_dir = WA_DIR_OUT;
1644         }
1645 
1646         wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR;
1647 
1648         wr->wr_reqp = (usb_opaque_t)curr_intr_reqp;
1649 
1650         wr->wr_timeout = (intr_reqp->intr_timeout == 0) ?
1651             WA_RPIPE_DEFAULT_TIMEOUT : intr_reqp->intr_timeout;
1652         wr->wr_cb = wusb_wa_handle_intr;
1653 
1654         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1655             "wusb_wa_create_intr_wrapper: wr = 0x%p nseg = %d", (void *)wr,
1656             wr->wr_nsegs);
1657 
1658         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1659 
1660         return (wr);
1661 }
1662 
1663 /*
1664  * Setup the transfer request structure for a segment
1665  * len = transfer request structure length
1666  *      - see section 8.3.3.1 and 8.3.3.2
1667  */
1668 void
1669 wusb_wa_setup_trans_req(wusb_wa_trans_wrapper_t *wr, wusb_wa_seg_t *seg,
1670         uint8_t len)
1671 {
1672         mblk_t          *data = seg->seg_trans_reqp->bulk_data;
1673         uint8_t         *trans_req = data->b_wptr;
1674 
1675         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1676             "wusb_wa_setup_trans_req: wr = 0x%p len = %d segnum = 0x%x",
1677             (void*)wr, len, seg->seg_num);
1678 
1679         bzero(trans_req, len);
1680         trans_req[0] = len;
1681         trans_req[1] = wr->wr_type;
1682         trans_req[2] = wr->wr_rp->rp_descr.wRPipeIndex;
1683         trans_req[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8;
1684         trans_req[4] = seg->seg_id;  /* dwTransferID */
1685         trans_req[5] = seg->seg_id >> 8;
1686         trans_req[6] = seg->seg_id >> 16;
1687         trans_req[7] = seg->seg_id >> 24;
1688         trans_req[8] = seg->seg_len;
1689         trans_req[9] = seg->seg_len >> 8;
1690         trans_req[10] = seg->seg_len >> 16;
1691         trans_req[11] = seg->seg_len >> 24;
1692         trans_req[12] = seg->seg_num;
1693 
1694         /*
1695          * 8-byte setupdata only for the first segment of a ctrl
1696          * transfer request
1697          */
1698         if (wr->wr_type == WA_XFER_REQ_TYPE_CTRL) {
1699                 usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)wr->wr_reqp;
1700 
1701                 /* what is the unsecured flag for ? */
1702                 trans_req[13] = wr->wr_dir | WA_CTRL_SECRT_REGULAR;
1703                 if ((seg->seg_num & 0x7f) == 0) {
1704                         /* only send baSetupDate on the first segment */
1705                         trans_req[16] = ctrl_req->ctrl_bmRequestType;
1706                         trans_req[17] = ctrl_req->ctrl_bRequest;
1707                         trans_req[18] = ctrl_req->ctrl_wValue;
1708                         trans_req[19] = ctrl_req->ctrl_wValue >> 8;
1709                         trans_req[20] = ctrl_req->ctrl_wIndex;
1710                         trans_req[21] = ctrl_req->ctrl_wIndex >> 8;
1711                         trans_req[22] = ctrl_req->ctrl_wLength;
1712                         trans_req[23] = ctrl_req->ctrl_wLength >> 8;
1713 
1714                 }
1715                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1716                     "wusb_wa_setup_trans_req: Ctrl segment = %02x",
1717                     seg->seg_num);
1718 
1719                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1720                     "wusb_wa_setup_trans_req: Ctrl Setup Data: "
1721                     "%02x %02x %02x %02x %02x %02x %02x %02x",
1722                     trans_req[16], trans_req[17], trans_req[18],
1723                     trans_req[19], trans_req[20], trans_req[21],
1724                     trans_req[22], trans_req[23]);
1725         }
1726         data->b_wptr += len;
1727 }
1728 
1729 /*
1730  * WA bulk pipe callbacks
1731  *   wusb_wa_trans_bulk_cb: transfer request stage normal callback
1732  *   wusb_wa_trans_bulk_exc_cb: transfer request stage exceptional callback
1733  *
1734  *   wusb_wa_data_bulk_cb: transfer data stage normal callback
1735  *   wusb_wa_data_bulk_exc_cb: transfer data stage exceptional callback
1736  *
1737  * see WUSB1.0 8.3.3 for details
1738  */
1739 void
1740 wusb_wa_trans_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1741 {
1742         wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1743         wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1744 
1745         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1746             "wusb_wa_trans_bulk_cb: ph=%p req=0x%p cr=%d", (void*)ph,
1747             (void*)req, req->bulk_completion_reason);
1748 
1749         mutex_enter(&wr->wr_rp->rp_mutex);
1750 
1751         /* callback returned, this seg can be freed */
1752         seg->seg_trans_req_state = 0;
1753 
1754         cv_signal(&seg->seg_trans_cv);
1755         mutex_exit(&wr->wr_rp->rp_mutex);
1756 }
1757 
1758 void
1759 wusb_wa_trans_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1760 {
1761         wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1762         wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1763 
1764         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1765             "wusb_wa_trans_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph,
1766             (void *)req, req->bulk_completion_reason);
1767 
1768         mutex_enter(&wr->wr_rp->rp_mutex);
1769 
1770         /* callback returned, this seg can be freed */
1771         seg->seg_trans_req_state = 0;
1772 
1773         cv_signal(&seg->seg_trans_cv);
1774         mutex_exit(&wr->wr_rp->rp_mutex);
1775 }
1776 
1777 void
1778 wusb_wa_data_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1779 {
1780         wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1781         wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1782 
1783         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1784             "wusb_wa_data_bulk_cb: ph=%p req=0x%p cr=%d", (void *)ph,
1785             (void *)req, req->bulk_completion_reason);
1786 
1787         mutex_enter(&wr->wr_rp->rp_mutex);
1788 
1789         /* callback returned, this seg can be freed */
1790         seg->seg_data_req_state = 0;
1791 
1792         cv_signal(&seg->seg_data_cv);
1793         mutex_exit(&wr->wr_rp->rp_mutex);
1794 }
1795 
1796 void
1797 wusb_wa_data_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1798 {
1799         wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1800         wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1801 
1802         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1803             "wusb_wa_data_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph,
1804             (void *)req, req->bulk_completion_reason);
1805 
1806         mutex_enter(&wr->wr_rp->rp_mutex);
1807 
1808         /* callback returned, this seg can be freed */
1809         seg->seg_data_req_state = 0;
1810 
1811         cv_signal(&seg->seg_data_cv);
1812         mutex_exit(&wr->wr_rp->rp_mutex);
1813 }
1814 
1815 /*
1816  * Setup all the transfer request segments, including the transfer request
1817  * stage and data stage for out transfer.
1818  * len = total size of payload data to transfer
1819  *      - for every segment, allocate a new bulk request for Transfer
1820  *        Request. Fill the request with the segment and wrapper data.
1821  *      - for every segment, allocate a new bulk request for data stage.
1822  *
1823  */
1824 int
1825 wusb_wa_setup_segs(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
1826         uint32_t len, mblk_t *data)
1827 {
1828         int             i, rval;
1829         wusb_wa_seg_t   *seg;
1830         usb_bulk_req_t  *trans_req, *data_req;
1831         uint8_t         trans_req_len;
1832         uint8_t         *p;
1833         wusb_wa_rpipe_hdl_t *hdl = NULL;
1834 
1835         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1836             "wusb_wa_setup_segs: wr = 0x%p len = %d data = 0x%p", (void *)wr,
1837             len, (void *)data);
1838 
1839         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1840 
1841         if (wr == NULL) {
1842                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1843                     "wusb_wa_setup_segs: invalid wr");
1844 
1845                 return (USB_INVALID_ARGS);
1846         }
1847 
1848         if ((len != 0) && (data != NULL)) {
1849                 p = data->b_rptr;
1850         }
1851 
1852         for (i = 0; i < wr->wr_nsegs; i++) {
1853                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*seg));
1854 
1855                 seg = &wr->wr_seg_array[i];
1856                 cv_init(&seg->seg_trans_cv, NULL, CV_DRIVER, NULL);
1857                 cv_init(&seg->seg_data_cv, NULL, CV_DRIVER, NULL);
1858                 seg->seg_wr = wr;
1859                 seg->seg_num = (uint8_t)i;   /* 0-based */
1860                 seg->seg_len = wr->wr_max_seglen;
1861                 if (i == (wr->wr_nsegs - 1)) {
1862                         seg->seg_num |= 0x80;        /* last segment */
1863                         seg->seg_len = len;
1864                 } else {
1865                         len -= seg->seg_len;
1866                 }
1867 
1868                 /*
1869                  * set seg_id, all segs are the same or unique ??
1870                  * now make all segs share the same id
1871                  */
1872                 seg->seg_id = wr->wr_id;
1873 
1874                 /* alloc transfer request and set values */
1875                 switch (wr->wr_type) {
1876                 case WA_XFER_REQ_TYPE_CTRL:
1877                         trans_req_len = WA_CTRL_REQ_LEN;
1878                         break;
1879                 case WA_XFER_REQ_TYPE_BULK_INTR:
1880                         trans_req_len = WA_BULK_INTR_REQ_LEN;
1881 
1882                         break;
1883                 default:
1884                         trans_req_len = 0;
1885                         break;
1886                 }
1887 
1888                 if (trans_req_len == 0) {
1889                         rval = USB_NOT_SUPPORTED;
1890                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1891                             "wusb_wa_setup_segs: trans len error");
1892 
1893                         goto error;
1894                 }
1895 
1896                 /* alloc transfer request for the ith seg */
1897                 trans_req = usb_alloc_bulk_req(wa_data->wa_dip,
1898                     trans_req_len, USB_FLAGS_NOSLEEP);
1899                 if (trans_req == NULL) {
1900                         rval = USB_NO_RESOURCES;
1901                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1902                             "wusb_wa_setup_segs: can't alloc_bulk_req");
1903 
1904                         goto error;
1905                 }
1906 
1907                 /* setup the ith transfer request */
1908                 trans_req->bulk_len = trans_req_len;
1909                 trans_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
1910                 trans_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1911                 trans_req->bulk_cb = wusb_wa_trans_bulk_cb;
1912                 trans_req->bulk_exc_cb = wusb_wa_trans_bulk_exc_cb;
1913                 trans_req->bulk_client_private = (usb_opaque_t)seg;
1914 
1915                 seg->seg_trans_reqp = trans_req;
1916                 wusb_wa_setup_trans_req(wr, seg, trans_req_len);
1917 
1918                 if (seg->seg_len != 0) {
1919                         /* alloc request for data stage */
1920                         data_req = usb_alloc_bulk_req(wa_data->wa_dip,
1921                             seg->seg_len, USB_FLAGS_NOSLEEP);
1922                         if (data_req == NULL) {
1923                                 rval = USB_NO_RESOURCES;
1924                                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI,
1925                                     whcdi_log_handle,
1926                                     "wusb_wa_setup_segs: can't alloc_bulk_req"
1927                                     " for data");
1928 
1929                                 goto error;
1930                         }
1931 
1932                         /* setup the ith data transfer */
1933                         data_req->bulk_len = seg->seg_len;
1934                         data_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
1935                         data_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1936 
1937                         data_req->bulk_cb = wusb_wa_data_bulk_cb;
1938                         data_req->bulk_exc_cb = wusb_wa_data_bulk_exc_cb;
1939                         data_req->bulk_client_private = (usb_opaque_t)seg;
1940 
1941                         seg->seg_data_reqp = data_req;
1942 
1943                         /*
1944                          * Copy data from client driver to bulk request for
1945                          * an OUT endpoint.
1946                          */
1947                         if (wr->wr_dir == WA_DIR_OUT) {
1948                                 ASSERT(data != NULL);
1949                                 /*
1950                                  * cannot increase data->b_rptr,
1951                                  * or scsa2usb panic at bulk out
1952                                  */
1953                                 ASSERT((intptr_t)((uintptr_t)data->b_wptr -
1954                                     (uintptr_t)p) >= seg->seg_len);
1955                                 bcopy(p,
1956                                     data_req->bulk_data->b_wptr,
1957                                     seg->seg_len);
1958                                 p += seg->seg_len;
1959 
1960                                 data_req->bulk_data->b_wptr += seg->seg_len;
1961                         }
1962                 }
1963 
1964                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*seg));
1965         }
1966 
1967         /* zero timeout means to wait infinitely */
1968         /*
1969          * if this is the first time this WR to be transfered,
1970          * we'll add it to its rpipe handle's timeout queue
1971          */
1972         if (wr->wr_timeout > 0) {
1973                 hdl = wr->wr_rp;
1974 
1975                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1976                     "wusb_wa_setup_segs: timeout=%d", wr->wr_timeout);
1977 
1978                 mutex_enter(&hdl->rp_mutex);
1979 
1980                 /* Add this new wrapper to the head of RPipe's timeout list */
1981                 if (hdl->rp_timeout_list) {
1982                         wr->wr_timeout_next = hdl->rp_timeout_list;
1983                 }
1984 
1985                 hdl->rp_timeout_list = wr;
1986 
1987                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1988 
1989                 mutex_exit(&hdl->rp_mutex);
1990         }
1991 
1992         return (USB_SUCCESS);
1993 
1994 error:
1995         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1996             "wusb_wa_setup_segs: fail, rval = %d", rval);
1997 
1998         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1999 
2000         mutex_enter(&hdl->rp_mutex);
2001         wusb_wa_free_segs(wr);
2002         mutex_exit(&hdl->rp_mutex);
2003 
2004         return (rval);
2005 }
2006 
2007 /* allocate transfer wrapper and setup all transfer segments */
2008 wusb_wa_trans_wrapper_t *
2009 wusb_wa_alloc_ctrl_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2010         usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
2011         usb_flags_t usb_flags)
2012 {
2013         wusb_wa_trans_wrapper_t *wr;
2014 
2015         wr = wusb_wa_create_ctrl_wrapper(wa_data, hdl, ph, ctrl_reqp,
2016             usb_flags);
2017 
2018         if (wr == NULL) {
2019                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2020                     "wusb_wa_alloc_ctrl_resources failed");
2021 
2022                 return (NULL);
2023         }
2024 
2025         if (wusb_wa_setup_segs(wa_data, wr, ctrl_reqp->ctrl_wLength,
2026             ctrl_reqp->ctrl_data) != USB_SUCCESS) {
2027                 wusb_wa_free_trans_wrapper(wr);
2028 
2029                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2030                     "wusb_wa_alloc_ctrl_resources failed to setup segs");
2031 
2032                 return (NULL);
2033         }
2034 
2035         return (wr);
2036 }
2037 
2038 /* allocate transfer wrapper and setup all transfer segments */
2039 wusb_wa_trans_wrapper_t *
2040 wusb_wa_alloc_bulk_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2041         usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
2042         usb_flags_t usb_flags)
2043 {
2044         wusb_wa_trans_wrapper_t *wr;
2045 
2046         wr = wusb_wa_create_bulk_wrapper(wa_data, hdl, ph, bulk_reqp,
2047             usb_flags);
2048 
2049         if (wr == NULL) {
2050 
2051                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2052                     "wusb_wa_alloc_bulk_resources: failed to create wr");
2053 
2054                 return (NULL);
2055         }
2056 
2057         if (wusb_wa_setup_segs(wa_data, wr, bulk_reqp->bulk_len,
2058             bulk_reqp->bulk_data) != USB_SUCCESS) {
2059                 wusb_wa_free_trans_wrapper(wr);
2060 
2061                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2062                     "wusb_wa_alloc_bulk_resources:failed to setup segs");
2063                 return (NULL);
2064         }
2065 
2066         return (wr);
2067 }
2068 
2069 /*
2070  * allocate transfer wrapper and setup all transfer segments
2071  * if it's an IN request, duplicate it.
2072  */
2073 wusb_wa_trans_wrapper_t *
2074 wusb_wa_alloc_intr_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2075         usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
2076         usb_flags_t usb_flags)
2077 {
2078         wusb_wa_trans_wrapper_t *wr;
2079 
2080         wr = wusb_wa_create_intr_wrapper(wa_data, hdl, ph, intr_reqp,
2081             usb_flags);
2082 
2083         if (wr == NULL) {
2084                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2085                     "wusb_wa_alloc_intr_resources: failed to create wr");
2086 
2087                 return (NULL);
2088         }
2089 
2090         if (wusb_wa_setup_segs(wa_data, wr, intr_reqp->intr_len,
2091             intr_reqp->intr_data) != USB_SUCCESS) {
2092                 wusb_wa_free_trans_wrapper(wr);
2093 
2094                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2095                     "wusb_wa_alloc_intr_resources: failed to setup segs");
2096 
2097                 return (NULL);
2098         }
2099 
2100         return (wr);
2101 }
2102 
2103 /* free the bulk request structures for all segments */
2104 void
2105 wusb_wa_free_segs(wusb_wa_trans_wrapper_t *wr)
2106 {
2107         int             i;
2108         wusb_wa_seg_t   *seg;
2109 
2110         ASSERT(mutex_owned(&wr->wr_rp->rp_mutex));
2111 
2112         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2113             "wusb_wa_free_segs: wr = 0x%p, segs=%p", (void *)wr,
2114             (void *)wr->wr_seg_array);
2115 
2116         if (wr->wr_seg_array == NULL) {
2117                 return;
2118         }
2119 
2120 
2121         for (i = 0; i < wr->wr_nsegs; i++) {
2122                 seg = &wr->wr_seg_array[i];
2123 
2124                 if (seg->seg_trans_reqp != NULL) {
2125                         while (seg->seg_trans_req_state == 1) {
2126                                 cv_wait(&seg->seg_trans_cv,
2127                                     &wr->wr_rp->rp_mutex);
2128                         }
2129                         /* free the bulk req for transfer request */
2130                         usb_free_bulk_req(seg->seg_trans_reqp);
2131                         seg->seg_trans_reqp = NULL;
2132                 }
2133 
2134                 if (seg->seg_data_reqp != NULL) {
2135                         while (seg->seg_data_req_state == 1) {
2136                                 cv_wait(&seg->seg_data_cv,
2137                                     &wr->wr_rp->rp_mutex);
2138                         }
2139                         /* free the bulk req for data transfer */
2140                         usb_free_bulk_req(seg->seg_data_reqp);
2141                         seg->seg_data_reqp = NULL;
2142                 }
2143 
2144                 cv_destroy(&seg->seg_trans_cv);
2145                 cv_destroy(&seg->seg_data_cv);
2146         }
2147 
2148         kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) * wr->wr_nsegs);
2149 
2150         wr->wr_seg_array = NULL;
2151         wr->wr_nsegs = 0;
2152 }
2153 
2154 /* free transfer wrapper */
2155 void
2156 wusb_wa_free_trans_wrapper(wusb_wa_trans_wrapper_t *wr)
2157 {
2158         wusb_wa_rpipe_hdl_t *hdl = NULL;
2159 
2160         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2161             "wusb_wa_free_trans_wrapper: wr = 0x%p", (void *)wr);
2162 
2163         if (wr == NULL) {
2164                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2165                     "wusb_wa_free_trans_wrapper: NULL wrapper");
2166                 return;
2167         }
2168 
2169         hdl = wr->wr_rp;
2170 
2171         mutex_enter(&hdl->rp_mutex);
2172 
2173         wusb_wa_remove_wr_from_timeout_list(hdl, wr);
2174 
2175         if (wr->wr_seg_array != NULL) {
2176                 wusb_wa_free_segs(wr);
2177                 kmem_free(wr->wr_seg_array,
2178                     sizeof (wusb_wa_seg_t) * wr->wr_nsegs);
2179         }
2180 
2181         if (wr->wr_id != 0) {
2182                 WA_FREE_ID(wr->wr_id);
2183         }
2184 
2185         cv_destroy(&wr->wr_cv);
2186 
2187         kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
2188 
2189         mutex_exit(&hdl->rp_mutex);
2190 }
2191 
2192 /* abort a transfer, refer to WUSB 1.0/8.3.3.5 */
2193 void
2194 wusb_wa_abort_req(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
2195         uint32_t id)
2196 {
2197         usb_bulk_req_t  *req;
2198         uint8_t         *p;
2199         int             rval;
2200 
2201         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2202             "wusb_wa_abort_req: wr = 0x%p", (void *)wr);
2203 
2204         req = usb_alloc_bulk_req(wa_data->wa_dip, WA_ABORT_REQ_LEN,
2205             USB_FLAGS_NOSLEEP);
2206         if (req == NULL) {
2207                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2208                     "wusb_wa_abort_req: alloc bulk req failed");
2209 
2210                 return;
2211         }
2212 
2213         req->bulk_len = WA_ABORT_REQ_LEN;
2214         req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
2215         req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
2216         p = req->bulk_data->b_wptr;
2217         p[0] = WA_ABORT_REQ_LEN;
2218         p[1] = WA_XFER_REQ_TYPE_ABORT;
2219         p[2] = wr->wr_rp->rp_descr.wRPipeIndex;
2220         p[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8;
2221         p[4] = (uint8_t)id;
2222         p[5] = (uint8_t)(id >> 8);
2223         p[6] = (uint8_t)(id >> 16);
2224         p[7] = (uint8_t)(id >> 24);
2225         req->bulk_data->b_wptr += WA_ABORT_REQ_LEN;
2226 
2227         mutex_exit(&wr->wr_rp->rp_mutex);
2228         rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req,
2229             USB_FLAGS_SLEEP);
2230         mutex_enter(&wr->wr_rp->rp_mutex);
2231         if (rval != USB_SUCCESS) {
2232                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2233                     "wusb_wa_abort_req: send abort req failed, rval = %d",
2234                     rval);
2235         }
2236         usb_free_bulk_req(req);
2237 }
2238 
2239 static void
2240 wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl,
2241         wusb_wa_trans_wrapper_t *tw)
2242 {
2243         wusb_wa_trans_wrapper_t *prev, *next;
2244         int ret = 0; /* debug only */
2245 
2246         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2247             "remove_wr_from_timeout_list: %p", (void *)tw);
2248 
2249         if (hdl->rp_timeout_list) {
2250                 if (hdl->rp_timeout_list == tw) {
2251                         hdl->rp_timeout_list = tw->wr_timeout_next;
2252                         tw->wr_timeout_next = NULL;
2253                         ret = 1;
2254                 } else {
2255                         prev = hdl->rp_timeout_list;
2256                         next = prev->wr_timeout_next;
2257 
2258                         while (next && (next != tw)) {
2259                                 prev = next;
2260                                 next = next->wr_timeout_next;
2261                         }
2262 
2263                         if (next == tw) {
2264                                 prev->wr_timeout_next = next->wr_timeout_next;
2265                                 tw->wr_timeout_next = NULL;
2266                                 ret = 1;
2267                         }
2268                 }
2269         }
2270 
2271         /* debug only */
2272         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2273             "remove_wr_from_timeout_list: %p, on the list:%d",
2274             (void *)tw, ret);
2275 }
2276 
2277 /* start timer on a rpipe */
2278 void
2279 wusb_wa_start_xfer_timer(wusb_wa_rpipe_hdl_t *hdl)
2280 {
2281         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2282             "wusb_wa_start_xfer_timer: rpipe hdl = 0x%p", (void *)hdl);
2283 
2284         ASSERT(mutex_owned(&hdl->rp_mutex));
2285 
2286         /*
2287          * wr_timeout is in Seconds
2288          */
2289         /*
2290          * Start the rpipe's timer only if currently timer is not
2291          * running and if there are transfers on the rpipe.
2292          * The timer will be per rpipe.
2293          *
2294          * The RPipe's timer expires every 1s. When this timer expires, the
2295          * handler gets called and will decrease every pending transfer
2296          * wrapper's timeout value.
2297          */
2298         if ((!hdl->rp_timer_id) && (hdl->rp_timeout_list)) {
2299                 hdl->rp_timer_id = timeout(wusb_wa_xfer_timeout_handler,
2300                     (void *)hdl, drv_usectohz(1000000));
2301         }
2302 }
2303 
2304 /* transfer timeout handler */
2305 void
2306 wusb_wa_xfer_timeout_handler(void *arg)
2307 {
2308         wusb_wa_rpipe_hdl_t     *hdl = (wusb_wa_rpipe_hdl_t *)arg;
2309         wusb_wa_trans_wrapper_t *wr = NULL;
2310         wusb_wa_trans_wrapper_t *next = NULL;
2311         wusb_wa_data_t          *wa_data = NULL;
2312         int                     rval;
2313         uint8_t                 rp_status;
2314         wusb_wa_trans_wrapper_t *expire_list = NULL;
2315 
2316         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2317             "wusb_wa_xfer_timeout_handler: rphdl = 0x%p ", (void *)hdl);
2318 
2319         mutex_enter(&hdl->rp_mutex);
2320 
2321         /*
2322          * Check whether still timeout handler is valid.
2323          */
2324         if (hdl->rp_timer_id != 0) {
2325 
2326                 /* Reset the timer id to zero */
2327                 hdl->rp_timer_id = 0;
2328         } else {
2329                 mutex_exit(&hdl->rp_mutex);
2330 
2331                 return;
2332         }
2333 
2334         /*
2335          * Check each transfer wrapper on this RPipe's timeout queue
2336          * Actually, due to USBA's limitation and queueing, there's only one
2337          * usba_request submitted to HCD at a specific pipe. Hence, only one
2338          * WR can be on this RPipe's list at any moment.
2339          */
2340         wr = hdl->rp_timeout_list;
2341         while (wr) {
2342                 next = wr->wr_timeout_next;
2343 
2344                 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2345                     "wusb_wa_xfer_timeout_handler: rhdl=0x%p"
2346                     " wr=0x%p(to=%d) nxt=0x%p", (void *)hdl, (void *)wr,
2347                     wr->wr_timeout, (void *)next);
2348 
2349                 /*
2350                  * 1 second passed. Decrease every transfer wrapper's
2351                  * timeout value. If the timeout < 0 (expired), remove this
2352                  * wrapper from the timeout list and put it on the
2353                  * expire_list.
2354                  */
2355                 wr->wr_timeout--;
2356                 if (wr->wr_timeout <= 0) {
2357                         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2358                             "wusb_wa_xfer_timeout_handler: 0x%p time out",
2359                             (void *)wr);
2360 
2361                         /* remove it from the rpipe's timeout list */
2362                         wusb_wa_remove_wr_from_timeout_list(hdl, wr);
2363 
2364                         /* put it on the expired list */
2365                         wr->wr_timeout_next = expire_list;
2366                         expire_list = wr;
2367 
2368                 }
2369 
2370                 wr = next;
2371         }
2372 
2373         /* Restart this RPipe's timer */
2374         wusb_wa_start_xfer_timer(hdl);
2375 
2376         /* timeout handling */
2377         wr = expire_list;
2378         while (wr) {
2379                 next = wr->wr_timeout_next;
2380 
2381                 /* other thread shouldn't continue processing it */
2382                 wr->wr_state = WR_TIMEOUT;
2383 
2384                 wa_data = wr->wr_wa_data;
2385 
2386                 mutex_exit(&hdl->rp_mutex);
2387                 rval = wusb_wa_get_rpipe_status(wa_data->wa_dip,
2388                     wa_data->wa_default_pipe, hdl->rp_descr.wRPipeIndex,
2389                     &rp_status);
2390                 mutex_enter(&hdl->rp_mutex);
2391 
2392                 if (rval != USB_SUCCESS) {
2393                         /* reset WA perhaps? */
2394                         hdl->rp_state = WA_RPIPE_STATE_ERROR;
2395                         hdl->rp_curr_wr = NULL;
2396                         mutex_exit(&hdl->rp_mutex);
2397                         wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 1);
2398                         mutex_enter(&hdl->rp_mutex);
2399 
2400                         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2401                             "wusb_wa_xfer_timeout_handler: fail to get"
2402                             " rpipe status, rval = %d", rval);
2403 
2404                         goto continuing;
2405                 }
2406                 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2407                     "wusb_wa_xfer_timeout_handler: rpstat=0x%02x, wr=0x%p,"
2408                     " wr_state=%d", rp_status, (void *)wr, wr->wr_state);
2409 
2410                 if (!(rp_status & WA_RPIPE_IDLE)) {
2411                 /*
2412                  * If RP is not idle, then it must be processing this WR.
2413                  * Abort this request to make the RPipe idle.
2414                  */
2415                         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2416                             "wusb_wa_xfer_timeout_handler: rp not idle");
2417 
2418                         mutex_exit(&hdl->rp_mutex);
2419                         rval = wusb_wa_rpipe_abort(wa_data->wa_dip,
2420                             wa_data->wa_default_pipe, hdl);
2421                         mutex_enter(&hdl->rp_mutex);
2422 
2423                         USB_DPRINTF_L3(DPRINT_MASK_WHCDI,
2424                             whcdi_log_handle,
2425                             "wusb_wa_xfer_timeout_handler: abort rpipe"
2426                             " fail rval = %d", rval);
2427 
2428                         if (rval == 0) {
2429                                 /*
2430                                  * wait for the result thread to get
2431                                  * Aborted result. If this wr hasn't been
2432                                  * aborted, wait it.
2433                                  */
2434                                 if ((wr->wr_has_aborted == 0) &&
2435                                     (cv_reltimedwait(&wr->wr_cv, &hdl->rp_mutex,
2436                                     drv_usectohz(100 * 1000), TR_CLOCK_TICK)
2437                                     >= 0)) {
2438                                     /* 100ms, random number, long enough? */
2439 
2440                                         /* the result thread has processed it */
2441                                         goto continuing;
2442                                 }
2443 
2444                                 USB_DPRINTF_L3(DPRINT_MASK_WHCDI,
2445                                     whcdi_log_handle,
2446                                     "wusb_wa_xfer_timeout_handler: result"
2447                                     " thread can't get the aborted request");
2448                         }
2449                 }
2450 
2451                 /*
2452                  * 1)The Rpipe is idle, OR,
2453                  * 2)rpipe_abort fails, OR,
2454                  * 3)The result thread hasn't got an aborted result in 100ms,
2455                  * most likely the result is lost. We can not depend on WA to
2456                  * return result for this aborted request. The WA seems not
2457                  * always returning such result. This will cause some hcdi
2458                  * ops hang.
2459                  */
2460                 hdl->rp_state = WA_RPIPE_STATE_IDLE;
2461                 hdl->rp_curr_wr = NULL;
2462 
2463                 /* release this WR's occupied req */
2464                 hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
2465                 cv_signal(&hdl->rp_cv);
2466 
2467                 mutex_exit(&hdl->rp_mutex);
2468 
2469                 wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 0);
2470                 mutex_enter(&hdl->rp_mutex);
2471 
2472 continuing:
2473                 wr = next;
2474         }
2475 
2476         mutex_exit(&hdl->rp_mutex);
2477 }
2478 
2479 /* stop timer */
2480 void
2481 wusb_wa_stop_xfer_timer(wusb_wa_trans_wrapper_t *wr)
2482 {
2483         wusb_wa_rpipe_hdl_t     *hdl = wr->wr_rp;
2484         timeout_id_t            timer_id;
2485 
2486         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2487             "wusb_wa_stop_xfer_timer: wr = 0x%p", (void *)wr);
2488 
2489         ASSERT(mutex_owned(&hdl->rp_mutex));
2490 
2491         if (hdl->rp_timer_id == 0) {
2492 
2493                 return;
2494         }
2495 
2496         timer_id = hdl->rp_timer_id;
2497         hdl->rp_timer_id = 0;
2498         mutex_exit(&hdl->rp_mutex);
2499 
2500         (void) untimeout(timer_id);
2501 
2502         mutex_enter(&hdl->rp_mutex);
2503 }
2504 
2505 
2506 /*
2507  * send transfer request and data to the bulk out pipe
2508  *
2509  * General transfer function for WA transfer, see Section 8.3.3.
2510  */
2511 /* ARGSUSED */
2512 int
2513 wusb_wa_wr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2514     wusb_wa_trans_wrapper_t *wr, usb_flags_t usb_flags)
2515 {
2516         int             i, rval;
2517         uint8_t         curr_seg;
2518         usb_bulk_req_t  *req;
2519 
2520         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2521             "wusb_wa_wr_xfer: wr = 0x%p", (void *)wr);
2522 
2523         ASSERT(wr->wr_seg_array != NULL);
2524 
2525         ASSERT(mutex_owned(&hdl->rp_mutex));
2526 
2527         if (hdl->rp_state == WA_RPIPE_STATE_IDLE) {
2528                 hdl->rp_state = WA_RPIPE_STATE_ACTIVE;
2529                 hdl->rp_curr_wr = wr;
2530         }
2531         curr_seg = wr->wr_curr_seg;
2532 
2533         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2534             "wusb_wa_wr_xfer: curr_seg = %d, avail_req = %d", curr_seg,
2535             hdl->rp_avail_reqs);
2536 
2537         /*
2538          * For every segment,
2539          *      Step 1: contruct a bulk req containing Transfer
2540          *              Request(T8-12 and T8-10)
2541          *      Step 2: alloc another bulk req if there's any data
2542          *              for OUT endpoints.
2543          *
2544          *      For IN endpoints, the data is returned in the
2545          *      GetResult thread.
2546          * Just throw as many as maximum available requests to the RPipe.
2547          * If the avail_req is zero, wait!
2548          *
2549          * When a request is finished, the avail_req will be increased
2550          * in the result thread.
2551          */
2552         for (i = curr_seg; i < wr->wr_nsegs; i++) {
2553                 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2554                     "wusb_wa_wr_xfer: wr=%p curr_seg = %d, avail_req = %d,"
2555                     " dir=%s", (void *)wr, curr_seg, hdl->rp_avail_reqs,
2556                     (wr->wr_dir == WA_DIR_IN)?"IN":"OUT");
2557 
2558                 /* waiting for available requests if wr is still good */
2559                 while ((hdl->rp_avail_reqs == 0) && (wr->wr_state == 0)) {
2560                         rval = cv_wait_sig(&hdl->rp_cv, &hdl->rp_mutex);
2561                 }
2562 
2563                 if ((wr->wr_curr_seg - wr->wr_seg_done) >= 1) {
2564                         /* send only one segment */
2565 
2566                         break;
2567                 }
2568 
2569                 if (wr->wr_state != 0) {
2570                 /* wr transfer error, don't continue */
2571                         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2572                             "wusb_wa_wr_xfer: wr_state!=0(%d)", wr->wr_state);
2573 
2574                         break;
2575                 }
2576 
2577                 req = wr->wr_seg_array[i].seg_trans_reqp;
2578                 ASSERT(req != NULL);
2579 
2580                 mutex_exit(&hdl->rp_mutex);
2581                 /* send ith transfer request */
2582                 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0);
2583                 mutex_enter(&hdl->rp_mutex);
2584                 if (rval != USB_SUCCESS) {
2585                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2586                             "wusb_wa_wr_xfer: send transfer request %d failed,"
2587                             "rv=%d", i, rval);
2588 
2589                         wr->wr_seg_array[i].seg_trans_req_state = 0; /* clear */
2590 
2591                         if (i == 0) {
2592                                 /* no xfer in processing */
2593                                 hdl->rp_state = WA_RPIPE_STATE_IDLE;
2594                                 hdl->rp_curr_wr = NULL;
2595 
2596                                 return (rval);
2597                         }
2598                         wusb_wa_abort_req(wa_data, wr, wr->wr_id);
2599                         wr->wr_state = WR_SEG_REQ_ERR;       /* sending tr error */
2600 
2601                         break;
2602                 }
2603                 wr->wr_seg_array[i].seg_trans_req_state = 1; /* submitted */
2604 
2605                 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2606                     "wusb_wa_wr_xfer: seg(%d) request(0x%p) sent,"
2607                     " avail_req = %d", i, (void*)req, hdl->rp_avail_reqs);
2608 
2609                 hdl->rp_avail_reqs--;
2610 
2611                 /* Get data in the GetResult thread for IN eps */
2612                 if (wr->wr_dir == WA_DIR_IN) {
2613                         wr->wr_curr_seg++;
2614 
2615                         /* only send data for out request */
2616                         continue;
2617                 }
2618 
2619                 req = wr->wr_seg_array[i].seg_data_reqp;
2620                 if (req == NULL) {
2621                         /* no data stage */
2622                         wr->wr_curr_seg++;
2623 
2624                         continue;
2625                 }
2626 
2627                 wr->wr_seg_array[i].seg_data_req_state = 1; /* submitted */
2628                 mutex_exit(&hdl->rp_mutex);
2629                 /* send ith data asynchronously */
2630                 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0);
2631                 mutex_enter(&hdl->rp_mutex);
2632                 if (rval != USB_SUCCESS) {
2633                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2634                             "wusb_wa_wr_xfer: send transfer data %d failed",
2635                             i);
2636 
2637                         wr->wr_seg_array[i].seg_data_req_state = 0; /* clear */
2638 
2639                         wusb_wa_abort_req(wa_data, wr, wr->wr_id);
2640                         wr->wr_state = WR_SEG_DAT_ERR; /* sending data error */
2641 
2642                         /* not inc rp_avail_reqs until callback */
2643 
2644                         break;
2645                 }
2646 
2647                 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2648                     "wusb_wa_wr_xfer: seg(%d) data(0x%p) sent, avail_req = %d",
2649                     i, (void*)req, hdl->rp_avail_reqs);
2650 
2651                 wr->wr_curr_seg++;
2652         }
2653 
2654         /* start timer */
2655         wusb_wa_start_xfer_timer(hdl);
2656         /*
2657          * return success even if the xfer is not complete, the callback
2658          * will only continue sending segs when (wr_error_state = 0 &&
2659          * wr_curr_seg < wr_nsegs)
2660          */
2661         return (USB_SUCCESS);
2662 }
2663 
2664 /*
2665  * submit wr according to rpipe status
2666  *      - check RPipe state
2667  *      - call general WA transfer function to do transfer
2668  *
2669  * usba only submits one transfer to the host controller per pipe at a time
2670  * and starts next when the previous one completed. So the hwahc now
2671  * assumes one transfer per rpipe at a time. This won't be necessary to
2672  * change unless the usba scheme is changed.
2673  */
2674 int
2675 wusb_wa_submit_ctrl_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2676         wusb_wa_trans_wrapper_t *wr, usb_ctrl_req_t *ctrl_reqp,
2677         usb_flags_t usb_flags)
2678 {
2679         int             rval;
2680 
2681         mutex_enter(&hdl->rp_mutex);
2682         switch (hdl->rp_state) {
2683         case WA_RPIPE_STATE_IDLE:
2684                 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
2685                 break;
2686         case WA_RPIPE_STATE_ACTIVE:
2687                 /* only allow one req at a time, this should not happen */
2688         default:
2689                 rval = USB_PIPE_ERROR;
2690                 break;
2691         }
2692         mutex_exit(&hdl->rp_mutex);
2693 
2694         if (rval != USB_SUCCESS) {
2695                 if (ctrl_reqp->ctrl_completion_reason == USB_CR_OK) {
2696                         ctrl_reqp->ctrl_completion_reason = usba_rval2cr(rval);
2697                 }
2698                 mutex_enter(&hdl->rp_mutex);
2699                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2700                     "wusb_wa_submit_ctrl_wr:fail, reqp=0x%p, rpstat=%d, rv=%d",
2701                     (void*)ctrl_reqp, hdl->rp_state, rval);
2702 
2703                 mutex_exit(&hdl->rp_mutex);
2704 
2705                 wusb_wa_free_trans_wrapper(wr);
2706         }
2707 
2708         /* In other cases, wr will be freed in callback */
2709         return (rval);
2710 }
2711 
2712 /*
2713  * Transfer a control request:
2714  *      - allocate a transfer wrapper(TW) for this request
2715  *      - submit this TW
2716  */
2717 int
2718 wusb_wa_ctrl_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2719         usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
2720         usb_flags_t usb_flags)
2721 {
2722         int                     rval;
2723         wusb_wa_trans_wrapper_t *wr;
2724 
2725         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2726             "wusb_wa_ctrl_xfer: ph = 0x%p reqp = 0x%p",
2727             (void*)ph, (void*)ctrl_reqp);
2728 
2729         wr = wusb_wa_alloc_ctrl_resources(wa_data, hdl, ph, ctrl_reqp,
2730             usb_flags);
2731         if (wr == NULL) {
2732                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2733                     "wusb_wa_ctrl_req: alloc ctrl resource failed");
2734 
2735                 return (USB_NO_RESOURCES);
2736         }
2737 
2738         rval = wusb_wa_submit_ctrl_wr(wa_data, hdl, wr, ctrl_reqp, usb_flags);
2739         if (rval != USB_SUCCESS) {
2740                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2741                     "wusb_wa_submit_ctrl_wr: submit ctrl req failed, rval = %d",
2742                     rval);
2743         }
2744 
2745         return (rval);
2746 }
2747 
2748 /*
2749  * submit wr according to rpipe status
2750  *
2751  * usba only submits one transfer to the host controller per pipe at a time
2752  * and starts next when the previous one completed. So the hwahc now
2753  * assumes one transfer per rpipe at a time. This won't be necessary to
2754  * change unless the usba scheme is changed.
2755  */
2756 int
2757 wusb_wa_submit_bulk_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2758         wusb_wa_trans_wrapper_t *wr, usb_bulk_req_t *bulk_reqp,
2759         usb_flags_t usb_flags)
2760 {
2761         int             rval;
2762 
2763         mutex_enter(&hdl->rp_mutex);
2764         switch (hdl->rp_state) {
2765         case WA_RPIPE_STATE_IDLE:
2766                 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
2767                 break;
2768         case WA_RPIPE_STATE_ACTIVE:
2769                 /* only allow one req at a time, this should not happen */
2770         default:
2771                 rval = USB_PIPE_ERROR;
2772                 break;
2773         }
2774         mutex_exit(&hdl->rp_mutex);
2775 
2776         if (rval != USB_SUCCESS) {
2777                 if (bulk_reqp->bulk_completion_reason == USB_CR_OK) {
2778                         bulk_reqp->bulk_completion_reason = usba_rval2cr(rval);
2779                 }
2780                 wusb_wa_free_trans_wrapper(wr);
2781         }
2782 
2783         /* In other cases, wr will be freed in callback */
2784         return (rval);
2785 }
2786 
2787 /*
2788  * WA general bulk transfer
2789  *      - allocate bulk resources
2790  *      - submit the bulk request
2791  */
2792 int
2793 wusb_wa_bulk_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2794         usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
2795         usb_flags_t usb_flags)
2796 {
2797         int                     rval;
2798         wusb_wa_trans_wrapper_t *wr;
2799 
2800         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2801             "wusb_wa_bulk_xfer: ph = 0x%p reqp = 0x%p",
2802             (void *)ph, (void *)bulk_reqp);
2803 
2804         wr = wusb_wa_alloc_bulk_resources(wa_data, hdl, ph, bulk_reqp,
2805             usb_flags);
2806         if (wr == NULL) {
2807                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2808                     "wusb_wa_bulk_xfer: alloc bulk resource failed");
2809 
2810                 return (USB_NO_RESOURCES);
2811         }
2812 
2813         rval = wusb_wa_submit_bulk_wr(wa_data, hdl, wr, bulk_reqp,
2814             usb_flags);
2815         if (rval != USB_SUCCESS) {
2816                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2817                     "wusb_wa_bulk_req: submit bulk req failed, rval = %d",
2818                     rval);
2819         }
2820 
2821         return (rval);
2822 }
2823 
2824 /*
2825  * submit wr according to rpipe status
2826  *
2827  * usba only submits one transfer to the host controller per pipe at a time
2828  * and starts next when the previous one completed. So the hwahc now
2829  * assumes one transfer per rpipe at a time. This won't be necessary to
2830  * change unless the usba scheme is changed.
2831  */
2832 int
2833 wusb_wa_submit_intr_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2834         wusb_wa_trans_wrapper_t *wr, usb_intr_req_t *intr_reqp,
2835         usb_flags_t usb_flags)
2836 {
2837         int             rval;
2838 
2839         mutex_enter(&hdl->rp_mutex);
2840         switch (hdl->rp_state) {
2841         case WA_RPIPE_STATE_IDLE:
2842                 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
2843                 break;
2844         case WA_RPIPE_STATE_ACTIVE:
2845                 /* only allow one req at a time, this should not happen */
2846         default:
2847                 rval = USB_PIPE_ERROR;
2848                 break;
2849         }
2850         mutex_exit(&hdl->rp_mutex);
2851 
2852         if (rval != USB_SUCCESS) {
2853                 if (intr_reqp->intr_completion_reason == USB_CR_OK) {
2854                         intr_reqp->intr_completion_reason = usba_rval2cr(rval);
2855                 }
2856                 wusb_wa_free_trans_wrapper(wr);
2857         }
2858 
2859         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2860             "wusb_wa_submit_intr_wr: submit intr req, rval = %d", rval);
2861 
2862         /* In other cases, wr will be freed in callback */
2863         return (rval);
2864 }
2865 
2866 /*
2867  * do intr xfer
2868  *
2869  * Now only one time intr transfer is supported. intr polling is not
2870  * supported.
2871  */
2872 int
2873 wusb_wa_intr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2874         usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
2875         usb_flags_t usb_flags)
2876 {
2877         int                     rval;
2878         wusb_wa_trans_wrapper_t *wr;
2879 
2880         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2881             "wusb_wa_intr_xfer: ph = 0x%p reqp = 0x%p",
2882             (void *)ph, (void *)intr_reqp);
2883 
2884         wr = wusb_wa_alloc_intr_resources(wa_data, hdl, ph, intr_reqp,
2885             usb_flags);
2886         if (wr == NULL) {
2887                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2888                     "wusb_wa_intr_req: alloc intr resource failed");
2889 
2890                 return (USB_NO_RESOURCES);
2891         }
2892 
2893         rval = wusb_wa_submit_intr_wr(wa_data, hdl, wr, intr_reqp,
2894             usb_flags);
2895         if (rval != USB_SUCCESS) {
2896                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2897                     "wusb_wa_intr_req: submit intr req failed, rval = %d",
2898                     rval);
2899 
2900                 return (rval);
2901         }
2902 
2903         /*
2904          * have successfully duplicate and queue one more request on
2905          * the pipe. Increase the pipe request count.
2906          */
2907         if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
2908                 mutex_enter(&ph->p_mutex);
2909 
2910                 /*
2911                  * this count will be decremented by usba_req_normal_cb
2912                  * or usba_req_exc_cb (called by hcdi_do_cb <-- usba_hcdi_cb)
2913                  */
2914                 ph->p_req_count++;
2915 
2916                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2917                     "wusb_wa_intr_req: p_req_cnt = %d", ph->p_req_count);
2918 
2919                 mutex_exit(&ph->p_mutex);
2920         }
2921 
2922         return (rval);
2923 }
2924 
2925 /*
2926  * For an IN transfer request, receive transfer data on bulk-in ept
2927  * The bulk_req has been allocated when allocating transfer resources
2928  */
2929 int
2930 wusb_wa_get_data(wusb_wa_data_t *wa_data, wusb_wa_seg_t *seg, uint32_t len)
2931 {
2932         usb_bulk_req_t          *req;
2933         int                     rval;
2934 
2935         if (len == 0) {
2936 
2937                 return (USB_SUCCESS);
2938         }
2939 
2940         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2941             "wusb_wa_get_data: get data for wr: 0x%p", (void *)seg->seg_wr);
2942 
2943         req = seg->seg_data_reqp;
2944         ASSERT(req != NULL);
2945 
2946         /* adjust bulk in length to actual length */
2947         req->bulk_len = len;
2948         rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req,
2949             USB_FLAGS_SLEEP);
2950 
2951         return (rval);
2952 }
2953 
2954 /*
2955  * to retrieve a transfer_wrapper by dwTransferID
2956  *
2957  * Though to search a list looks not so efficient, we have to give up
2958  * id32_lookup(). When a transfer segment is throwed to HWA device, we
2959  * can't anticipate when the result will be returned, even if we try to
2960  * abort it. If we have freed the transfer wrapper due to timeout, then
2961  * after a moment, that TW's segment is accomplished by hardware. If
2962  * id32_lookup() is used to look up corresponding TW, we'll get an invalid
2963  * address. Unfortunately, id32_lookup() can't judge validity of its
2964  * returned address.
2965  */
2966 wusb_wa_trans_wrapper_t *
2967 wusb_wa_retrieve_wr(wusb_wa_data_t *wa_data, uint32_t id)
2968 {
2969         wusb_wa_rpipe_hdl_t *rph;
2970         uint16_t        i;
2971         wusb_wa_trans_wrapper_t *tw;
2972 
2973         for (i = 0; i < wa_data->wa_num_rpipes; i++) {
2974                 rph = &wa_data->wa_rpipe_hdl[i];
2975 
2976                 mutex_enter(&rph->rp_mutex);
2977                 /* all outstanding TWs are put on the timeout list */
2978                 tw = rph->rp_timeout_list;
2979 
2980                 while (tw) {
2981                         if (tw->wr_id == id) {
2982                                 mutex_exit(&rph->rp_mutex);
2983                                 return (tw);
2984                         }
2985                         tw = tw->wr_timeout_next;
2986                 }
2987                 mutex_exit(&rph->rp_mutex);
2988         }
2989 
2990         return (NULL);
2991 }
2992 
2993 /* endlessly wait for transfer result on bulk-in ept and handle the result */
2994 int
2995 wusb_wa_get_xfer_result(wusb_wa_data_t *wa_data)
2996 {
2997         usb_bulk_req_t          *req;
2998         int                     rval;
2999         mblk_t                  *data;
3000         uint8_t                 *p;
3001         wa_xfer_result_t        result;
3002         wusb_wa_trans_wrapper_t *wr;
3003         wusb_wa_seg_t           *seg;
3004         uint8_t                 status;
3005         uint_t                  len;
3006         uint8_t                 lastseg = 0;
3007         usb_cr_t                cr;
3008         uint32_t                act_len;
3009         wusb_wa_rpipe_hdl_t     *hdl;
3010 
3011         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3012             "wusb_wa_get_xfer_result: started, wa=0x%p", (void*)wa_data);
3013 
3014         /* grab lock before accessing wa_data */
3015         mutex_enter(&wa_data->wa_mutex);
3016 
3017         len = wa_data->wa_bulkin_ept.wMaxPacketSize;
3018 
3019         req = usb_alloc_bulk_req(wa_data->wa_dip, len,
3020             USB_FLAGS_NOSLEEP);
3021         if (req == NULL) {
3022                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3023                     "wusb_wa_get_xfer_result: alloc bulk req failed");
3024 
3025                 mutex_exit(&wa_data->wa_mutex);
3026 
3027                 return (USB_NO_RESOURCES);
3028         }
3029 
3030         req->bulk_len = len;
3031         req->bulk_timeout = 0;
3032         req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK |
3033             USB_ATTRS_AUTOCLEARING;
3034 
3035         mutex_exit(&wa_data->wa_mutex);
3036 
3037         /* Get the Transfer Result head, see Table 8-14 */
3038         rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req,
3039             USB_FLAGS_SLEEP);
3040         if ((rval != USB_SUCCESS) || (req->bulk_data == NULL)) {
3041                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3042                     "wusb_wa_get_xfer_result: bulk xfer failed or "
3043                     "null data returned, rval=%d, req->bulk_data = %p",
3044                     rval, (void*)req->bulk_data);
3045                 usb_free_bulk_req(req);
3046 
3047                 return (rval);
3048         }
3049 
3050         data = req->bulk_data;
3051         p = data->b_rptr;
3052 
3053         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3054             "wusb_wa_get_xfer_result: received data len = %d",
3055             (int)MBLKL(data));
3056 
3057         if ((MBLKL(data) != WA_XFER_RESULT_LEN) ||
3058             (p[1] != WA_RESULT_TYPE_TRANSFER)) {
3059                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3060                     "wusb_wa_get_xfer_result: invalid xfer result, "
3061                     "len = %d, p0 = 0x%x, p1 = 0x%x, p6 = 0x%x",
3062                     (int)MBLKL(data), p[0], p[1], p[6]);
3063 
3064                 usb_free_bulk_req(req);
3065 
3066                 return (USB_SUCCESS); /* don't stop this thread */
3067         }
3068 
3069         /* Transfer result. Section 8.3.3.4 */
3070         (void) usb_parse_data("ccllccl", p, WA_XFER_RESULT_LEN, &result,
3071             sizeof (wa_xfer_result_t));
3072 
3073 
3074         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3075             "wusb_wa_get_xfer_result: id = 0x%x len = 0x%x nseg = 0x%02x"
3076             " status = 0x%02x(0x%02x)", result.dwTransferID,
3077             result.dwTransferLength, result.bTransferSegment,
3078             result.bTransferStatus, p[11]&0x0f);
3079 
3080         req->bulk_data = NULL; /* don't free it. we still need it */
3081         usb_free_bulk_req(req);
3082 
3083         status = result.bTransferStatus;
3084         if ((status & 0x3f) == WA_STS_NOT_FOUND) {
3085                 freemsg(data);
3086                 /*
3087                  * The result is just ignored since the transfer request
3088                  * has completed
3089                  */
3090                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3091                     "wusb_wa_get_xfer_result: TransferID not found");
3092 
3093                 return (USB_SUCCESS);
3094         }
3095 
3096         mutex_enter(&wa_data->wa_mutex);
3097         wr = wusb_wa_retrieve_wr(wa_data, result.dwTransferID);
3098         if ((wr == NULL)) {
3099         /* this id's corresponding WR may have been freed by timeout handler */
3100                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3101                     "wusb_wa_get_xfer_result: wr == deadbeef or NULL");
3102 
3103                 mutex_exit(&wa_data->wa_mutex);
3104                 freemsg(data);
3105 
3106                 return (USB_SUCCESS);
3107         }
3108 
3109         /* bit 7 is last segment flag */
3110         if ((result.bTransferSegment & 0x7f) >= wr->wr_nsegs) {
3111                 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3112                     "wusb_wa_get_xfer_result: error - "
3113                     " bTransferSegment(%d) > segment coutnts(%d)",
3114                     (result.bTransferSegment & 0x7f), wr->wr_nsegs);
3115 
3116                 goto err;
3117         }
3118 
3119         lastseg = result.bTransferSegment & 0x80;
3120         hdl = wr->wr_rp;
3121 
3122         mutex_enter(&hdl->rp_mutex);
3123         seg = &wr->wr_seg_array[result.bTransferSegment & 0x7f];
3124         seg->seg_status = result.bTransferStatus;
3125         act_len = seg->seg_actual_len = result.dwTransferLength;
3126 
3127         /*
3128          * if this is the last segment, we should not continue.
3129          * IMPT: we expect the WA deliver result sequentially.
3130          */
3131         seg->seg_done = (result.bTransferSegment) & 0x80;
3132 
3133         wr->wr_seg_done++;
3134         hdl->rp_avail_reqs++;
3135         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3136             "wusb_wa_get_xfer_result: wr = %p, rp=%p, avail_req=%d", (void*)wr,
3137             (void*)wr->wr_rp, hdl->rp_avail_reqs);
3138 
3139         cv_broadcast(&hdl->rp_cv);
3140 
3141         if (status & 0x40) {
3142                 status = 0; /* ignore warning, see Tab8-15 */
3143         }
3144         seg->seg_status = status;
3145 
3146         /* Error bit set */
3147         if (status & 0x80) {
3148                 /* don't change timeout error */
3149                 if (wr->wr_state != WR_TIMEOUT) {
3150                         wr->wr_state = WR_XFER_ERR;
3151                 }
3152 
3153                 /*
3154                  * The timeout handler is waiting, but the result thread will
3155                  * process this wr.
3156                  */
3157                 if ((wr->wr_state == WR_TIMEOUT) &&
3158                     (status & 0x3F) == WA_STS_ABORTED) {
3159                         wr->wr_has_aborted = 1;
3160                         cv_signal(&wr->wr_cv); /* to inform timeout hdler */
3161                 }
3162 
3163                 mutex_exit(&hdl->rp_mutex);
3164                 /* seg error, don't proceed with this WR */
3165                 goto err;
3166         }
3167 
3168         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3169             "wusb_wa_get_xfer_result: status = 0x%02x dir=%s",
3170             status, (wr->wr_dir == WA_DIR_IN)?"IN":"OUT");
3171 
3172         /*
3173          * for an IN endpoint and data length > 0 and no error, read in
3174          * the real data. Otherwise, for OUT EP, or data length = 0, or
3175          * segment error, don't read.
3176          */
3177         if ((wr->wr_dir == WA_DIR_IN) &&
3178             (act_len > 0) &&
3179             ((status & 0x3F) == 0)) { /* if segment error, don't read */
3180                 /* receive data */
3181                 mutex_exit(&hdl->rp_mutex);
3182                 mutex_exit(&wa_data->wa_mutex);
3183                 rval = wusb_wa_get_data(wa_data, seg, act_len);
3184                 mutex_enter(&wa_data->wa_mutex);
3185                 mutex_enter(&hdl->rp_mutex);
3186                 if (rval != USB_SUCCESS) {
3187                         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3188                             "wusb_wa_get_xfer_result: can't get seg data:%d",
3189                             rval);
3190 
3191                         mutex_exit(&hdl->rp_mutex);
3192 
3193                         goto err;
3194                 }
3195 
3196                 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3197                     "wusb_wa_get_xfer_result: get (%dB) data for IN ep",
3198                     act_len);
3199         }
3200 
3201         mutex_exit(&hdl->rp_mutex);
3202 
3203         mutex_exit(&wa_data->wa_mutex);
3204 
3205         /* check if the whole transfer has completed */
3206         wusb_wa_check_req_done(wa_data, wr, lastseg);
3207 
3208         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3209             "wusb_wa_get_xfer_result: ended");
3210 
3211         freemsg(data);
3212 
3213         return (USB_SUCCESS);
3214 
3215 err:
3216         mutex_exit(&wa_data->wa_mutex);
3217 
3218         mutex_enter(&hdl->rp_mutex);
3219         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3220             "wusb_wa_get_xfer_result: segment(%02x) error, abort wr 0x%p,"
3221             "wr_state=%d", result.bTransferSegment, (void*)wr, wr->wr_state);
3222 
3223         /* if it's timeout, just return the TIMEOUT error */
3224         if (wr->wr_state == WR_TIMEOUT) {
3225                 cr = USB_CR_TIMEOUT;
3226         } else {
3227                 cr = wusb_wa_sts2cr(status);
3228         }
3229 
3230         mutex_exit(&hdl->rp_mutex);
3231 
3232         wusb_wa_handle_error(wa_data, wr, cr);
3233 
3234         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3235             "wusb_wa_get_xfer_result: error end, cr=%d",
3236             cr);
3237 
3238         freemsg(data);
3239 
3240         return (USB_SUCCESS);
3241 }
3242 
3243 
3244 static void
3245 wusb_wa_handle_error(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3246     usb_cr_t cr)
3247 {
3248         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3249             "wusb_wa_handle_error: start");
3250 
3251         mutex_enter(&wr->wr_rp->rp_mutex);
3252         if (wr->wr_seg_done != wr->wr_curr_seg) {
3253         /* still segments pending, abort them */
3254                 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3255                     "wusb_wa_handle_error: segment err, abort other segs");
3256 
3257                 wusb_wa_abort_req(wa_data, wr, wr->wr_id);
3258         }
3259 
3260         wusb_wa_stop_xfer_timer(wr);
3261         wr->wr_rp->rp_state = WA_RPIPE_STATE_IDLE;
3262         wr->wr_rp->rp_curr_wr = NULL;
3263         mutex_exit(&wr->wr_rp->rp_mutex);
3264 
3265         wr->wr_cb(wa_data, wr, cr, 1);
3266 
3267         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3268             "wusb_wa_handle_error: error end, cr=%d",
3269             cr);
3270 }
3271 
3272 /*
3273  * Check if current request is done, if yes, do callback and move on to
3274  * next request; if there is any uncleared error, do callback to cleanup
3275  * the pipe
3276  */
3277 void
3278 wusb_wa_check_req_done(wusb_wa_data_t *wa_data,
3279     wusb_wa_trans_wrapper_t *wr, uint8_t lastseg)
3280 {
3281         wusb_wa_rpipe_hdl_t     *hdl = wr->wr_rp;
3282         wusb_wa_seg_t           *seg;
3283         int                     i, rval;
3284         usb_cr_t                cr;
3285 
3286         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3287             "wusb_wa_check_req_done: wr = 0x%p, lastseg=%02x",
3288             (void*)wr, lastseg);
3289 
3290         mutex_enter(&hdl->rp_mutex);
3291         /* not done: submitted segs not finished and lastseg not set */
3292         if ((wr->wr_seg_done != wr->wr_curr_seg) && (!lastseg)) {
3293                 mutex_exit(&hdl->rp_mutex);
3294 
3295                 return;
3296         }
3297 
3298         if (wr->wr_state != 0) { /* abort somewhere */
3299                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3300                     "wusb_wa_check_req_done: tw(%p) aborted somewhere",
3301                     (void*)wr);
3302                 cr = USB_CR_UNSPECIFIED_ERR;
3303 
3304                 goto reset;
3305         }
3306 
3307         /* check if there is any error */
3308         for (i = 0; i < wr->wr_curr_seg; i++) {
3309                 seg = &wr->wr_seg_array[i];
3310                 if (seg->seg_status != WA_STS_SUCCESS) {
3311                         /* what about short xfer? need to fix */
3312                         cr = wusb_wa_sts2cr(seg->seg_status);
3313                         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3314                             "wusb_wa_check_req_done: seg fail, status=%02x",
3315                             seg->seg_status);
3316 
3317                         goto reset;
3318                 }
3319 
3320                 if (seg->seg_done == 0x80) {
3321                 /* device has told this is the last segment, we're done */
3322                         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3323                             "wusb_wa_check_req_done: last seg");
3324 
3325                         goto done;
3326                 }
3327         }
3328 
3329         /* check if current request has completed */
3330         /*
3331          * Transfer another segment.
3332          *
3333          */
3334         if (wr->wr_curr_seg < wr->wr_nsegs) {
3335                 /* send the remained segments */
3336                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3337                     "wusb_wa_check_req_done: req not completed, restart");
3338 
3339                 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, wr->wr_flags);
3340                 if (rval != USB_SUCCESS) {
3341                         cr = usba_rval2cr(rval);
3342 
3343                         goto reset;
3344                 }
3345 
3346                 mutex_exit(&hdl->rp_mutex);
3347 
3348                 return;
3349         }
3350 
3351 done:
3352         wusb_wa_stop_xfer_timer(wr);
3353 
3354         /* release the occupied requests */
3355         hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
3356         cv_signal(&hdl->rp_cv);
3357 
3358         hdl->rp_state = WA_RPIPE_STATE_IDLE;
3359         hdl->rp_curr_wr = NULL;
3360         wr->wr_state = WR_FINISHED;
3361         mutex_exit(&hdl->rp_mutex);
3362 
3363         wr->wr_cb(wa_data, wr, USB_CR_OK, 0);
3364 
3365         /* Need to move on to next request? usba will do this */
3366         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3367             "wusb_wa_check_req_done: ended");
3368 
3369         return;
3370 
3371 reset:
3372         wusb_wa_stop_xfer_timer(wr);
3373 
3374         /* not necessary to reset the RPipe */
3375         hdl->rp_state = WA_RPIPE_STATE_IDLE;
3376         hdl->rp_curr_wr = NULL;
3377 
3378         hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
3379         cv_signal(&hdl->rp_cv);
3380 
3381         /* if it's timeout, just return the TIMEOUT error */
3382         if (wr->wr_state == WR_TIMEOUT)
3383                 cr = USB_CR_TIMEOUT;
3384 
3385         mutex_exit(&hdl->rp_mutex);
3386 
3387         wr->wr_cb(wa_data, wr, cr, 1);
3388         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3389             "wusb_wa_check_req_done: reset end");
3390 }
3391 
3392 /*
3393  * callback for ctrl transfer
3394  *
3395  * reset_flag: not support yet
3396  */
3397 void
3398 wusb_wa_handle_ctrl(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3399         usb_cr_t cr, uint_t reset_flag)
3400 {
3401         usb_ctrl_req_t  *req;
3402         usb_bulk_req_t  *bulk_req;
3403         mblk_t          *data, *bulk_data;
3404         int             i;
3405         size_t          len;
3406         wusb_wa_seg_t   *seg;
3407 
3408         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3409             "wusb_wa_handle_ctrl: wr = 0x%p, cr = 0x%x, flag=%d",
3410             (void*)wr, cr, reset_flag);
3411 
3412         req = (usb_ctrl_req_t *)wr->wr_reqp;
3413 
3414         if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
3415 
3416                 /* do callback */
3417                 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3418 
3419                 return;
3420         }
3421 
3422         mutex_enter(&wr->wr_rp->rp_mutex);
3423         data = req->ctrl_data;
3424         for (i = 0; i < wr->wr_nsegs; i++) {
3425                 seg = &wr->wr_seg_array[i];
3426                 /* copy received data to original req buffer */
3427                 bulk_req = (usb_bulk_req_t *)
3428                     wr->wr_seg_array[i].seg_data_reqp;
3429                 bulk_data = bulk_req->bulk_data;
3430                 len = MBLKL(bulk_data);
3431                 bcopy(bulk_data->b_rptr, data->b_wptr, len);
3432                 data->b_wptr += len;
3433                 if (len < wr->wr_seg_array[i].seg_len) {
3434                         /* short xfer */
3435                         break;
3436                 }
3437 
3438                 if (seg->seg_done == 0x80) {
3439                 /* last segment, finish */
3440                         break;
3441                 }
3442         }
3443 
3444         mutex_exit(&wr->wr_rp->rp_mutex);
3445         /* do callback */
3446         wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3447 }
3448 
3449 /*
3450  * callback for bulk transfer
3451  *
3452  * reset_flag: not support yet
3453  */
3454 void
3455 wusb_wa_handle_bulk(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3456         usb_cr_t cr, uint_t reset_flag)
3457 {
3458         usb_bulk_req_t  *req;
3459         usb_bulk_req_t  *bulk_req;
3460         mblk_t          *data, *bulk_data;
3461         int             i;
3462         size_t          len;
3463         wusb_wa_seg_t   *seg;
3464 
3465         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3466             "wusb_wa_handle_bulk: wr = 0x%p, cr = 0x%x, flag=%d",
3467             (void*)wr, cr, reset_flag);
3468 
3469         req = (usb_bulk_req_t *)wr->wr_reqp;
3470 
3471         if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
3472                 /* do callback */
3473                 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3474 
3475                 return;
3476         }
3477 
3478         mutex_enter(&wr->wr_rp->rp_mutex);
3479         data = req->bulk_data;
3480         for (i = 0; i < wr->wr_nsegs; i++) {
3481                 seg = &wr->wr_seg_array[i];
3482                 /* copy received data to original req buffer */
3483                 bulk_req = (usb_bulk_req_t *)
3484                     wr->wr_seg_array[i].seg_data_reqp;
3485                 bulk_data = bulk_req->bulk_data;
3486                 len = MBLKL(bulk_data);
3487                 bcopy(bulk_data->b_rptr, data->b_wptr, len);
3488                 data->b_wptr += len;
3489                 if (len < wr->wr_seg_array[i].seg_len) {
3490                         /* short xfer */
3491                         break;
3492                 }
3493 
3494                 if (seg->seg_done == 0x80) {
3495                 /* last segment, finish */
3496                         break;
3497                 }
3498         }
3499 
3500         mutex_exit(&wr->wr_rp->rp_mutex);
3501         /* do callback */
3502         wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3503 }
3504 
3505 int
3506 wa_submit_periodic_req(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph)
3507 {
3508         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3509             "wa_submit_periodic_req: wa_data=0x%p, ph=0x%p",
3510             (void*)wa_data, (void*)ph);
3511 
3512         return (wa_data->pipe_periodic_req(wa_data, ph));
3513 }
3514 
3515 /*
3516  * callback for intr transfer
3517  *
3518  * reset_flag: not support yet
3519  */
3520 void
3521 wusb_wa_handle_intr(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3522         usb_cr_t cr, uint_t reset_flag)
3523 {
3524         usb_intr_req_t  *req;
3525         usb_req_attrs_t attrs;
3526         usba_pipe_handle_data_t *ph = wr->wr_ph;
3527         usb_bulk_req_t  *bulk_req;
3528         mblk_t          *data, *bulk_data;
3529         int             i;
3530         size_t          len;
3531         int             rval;
3532         wusb_wa_seg_t   *seg;
3533 
3534         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3535             "wusb_wa_handle_intr: wr = 0x%p, cr = 0x%x, flag=%d",
3536             (void*)wr, cr, reset_flag);
3537 
3538         req = (usb_intr_req_t *)wr->wr_reqp;
3539         attrs = req->intr_attributes;
3540 
3541         if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
3542                 /* do callback */
3543                 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3544 
3545                 return;
3546         }
3547 
3548         mutex_enter(&wr->wr_rp->rp_mutex);
3549         /* copy data to client's buffer */
3550         data = req->intr_data;
3551         for (i = 0; i < wr->wr_nsegs; i++) {
3552                 seg = &wr->wr_seg_array[i];
3553                 /* copy received data to original req buffer */
3554                 bulk_req = (usb_bulk_req_t *)
3555                     wr->wr_seg_array[i].seg_data_reqp;
3556                 bulk_data = bulk_req->bulk_data;
3557                 len = MBLKL(bulk_data);
3558                 bcopy(bulk_data->b_rptr, data->b_wptr, len);
3559                 data->b_wptr += len;
3560                 if (len < wr->wr_seg_array[i].seg_len) {
3561                         /* short xfer */
3562                         break;
3563                 }
3564 
3565                 if (seg->seg_done & 0x80) {
3566 
3567                         break;
3568                 }
3569         }
3570 
3571         if (attrs & USB_ATTRS_ONE_XFER) {
3572         /* client requires ONE_XFER request, return */
3573                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3574                     "wusb_wa_handle_intr: ONE_XFER set");
3575 
3576                 mutex_exit(&wr->wr_rp->rp_mutex);
3577                 goto finish;
3578         }
3579 
3580         /* polling mode */
3581         mutex_exit(&wr->wr_rp->rp_mutex);
3582         rval = wa_submit_periodic_req(wa_data, ph);
3583         if (rval != USB_SUCCESS) {
3584                 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3585                     "wusb_wa_handle_intr: polling, fail to resubmit req");
3586 
3587                 goto finish;
3588         }
3589 
3590         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3591             "wusb_wa_handle_intr: polling, resubmit request, rv=%d", rval);
3592 
3593 finish:
3594         /* do callback */
3595         wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3596 
3597         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3598             "wusb_wa_handle_intr: end");
3599 }
3600 
3601 /*
3602  * free transfer wrapper
3603  * call host controller driver callback for completion handling
3604  *
3605  * This callback will call WA's specific callback function.
3606  * The callback functions should call usba_hcdi_cb() to pass request
3607  * back to client driver.
3608  */
3609 void
3610 wusb_wa_callback(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph,
3611     wusb_wa_trans_wrapper_t *wr, usb_cr_t cr)
3612 {
3613         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3614             "wusb_wa_callback: wr=0x%p, cr=0x%x, ph=0x%p, req = 0x%p",
3615             (void*)wr, cr, (void*)ph, (void*)((wr == NULL)?0:wr->wr_reqp));
3616 
3617         if (cr == USB_CR_FLUSHED) {
3618                 /*
3619                  * the wr is aborted. mark the rpipe as error,
3620                  * so that the periodic xfer callbacks will not submit
3621                  * further requests.
3622                  */
3623                 mutex_enter(&wr->wr_rp->rp_mutex);
3624                 wr->wr_rp->rp_state = WA_RPIPE_STATE_ERROR;
3625                 mutex_exit(&wr->wr_rp->rp_mutex);
3626         }
3627 
3628         wa_data->rpipe_xfer_cb(wa_data->wa_dip, ph, wr, cr);
3629 
3630         /*
3631          * need to consider carefully when to free wrapper
3632          * if the rpipe is reset, what to do with current wr in processing?
3633          */
3634         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3635             "wusb_wa_callback: hwahc callback finish for wr= 0x%p, free it",
3636             (void*)wr);
3637 
3638         wusb_wa_free_trans_wrapper(wr);
3639 }
3640 
3641 static struct {
3642         uint8_t status;
3643         usb_cr_t        cr;
3644 } sts2cr[] = {
3645         {WA_STS_SUCCESS,        USB_CR_OK},
3646         {WA_STS_HALTED,         USB_CR_STALL},
3647         {WA_STS_DATA_BUFFER_ERROR,      USB_CR_DATA_OVERRUN},
3648         {WA_STS_BABBLE,         USB_CR_DATA_UNDERRUN},
3649         {WA_STS_NOT_FOUND,      USB_CR_NOT_ACCESSED},
3650         {WA_STS_INSUFFICIENT_RESOURCE,  USB_CR_NO_RESOURCES},
3651         {0x80 | WA_STS_TRANSACTION_ERROR,       USB_CR_STALL},
3652         {0x40 | WA_STS_TRANSACTION_ERROR,       USB_CR_OK},
3653         {WA_STS_ABORTED,        USB_CR_FLUSHED},
3654         {WA_STS_RPIPE_NOT_READY,        USB_CR_DEV_NOT_RESP},
3655         {WA_STS_INVALID_REQ_FORMAT,     USB_CR_CRC},
3656         {WA_STS_UNEXPECTED_SEGMENT_NUM, USB_CR_UNEXP_PID},
3657         {WA_STS_RPIPE_TYPE_MISMATCH,    USB_CR_NOT_SUPPORTED},
3658         {WA_STS_PACKET_DISCARDED,       USB_CR_PID_CHECKFAILURE},
3659         {0xff,          0}      /* end */
3660 };
3661 
3662 /* translate transfer status to USB completion reason */
3663 usb_cr_t
3664 wusb_wa_sts2cr(uint8_t rawstatus)
3665 {
3666         int     i;
3667         uint8_t status;
3668 
3669         /* cares about bits5:0 in WUSB 1.0 */
3670         if ((rawstatus & 0x1f) == WA_STS_TRANSACTION_ERROR) {
3671                 status = rawstatus;
3672         } else {
3673                 status = rawstatus & 0x1f;
3674         }
3675 
3676         for (i = 0; sts2cr[i].status != 0xff; i++) {
3677                 if (sts2cr[i].status == status) {
3678 
3679                         return (sts2cr[i].cr);
3680                 }
3681         }
3682 
3683         return (USB_CR_UNSPECIFIED_ERR);
3684 }