/* * download firmware or command by control pipe */ static int wusb_df_send_data(wusb_df_state_t *wusbp, unsigned int address, const unsigned char *buffer, unsigned int size) { int error = DDI_FAILURE; usb_ctrl_setup_t setup; usb_cb_flags_t cb_flags; usb_cr_t cr; mblk_t *data = NULL; /* data for USBA */ uint16_t data_len; /* # of bytes want to write */ uint_t cnt; /* # of xfered bytes */ setup.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_DEV; setup.bRequest = 0xf0; setup.attrs = 0; for (cnt = 0; cnt < size; cnt += data_len) { data_len = min(size - cnt, 512); /* reuse previous mblk if possible */ if ((data = reallocb(data, data_len, 0)) == NULL) { return (USB_FAILURE); } bcopy(buffer + cnt, data->b_rptr, data_len); data->b_wptr += data_len; setup.wValue = (address + cnt) & 0xffff; setup.wIndex = ((address + cnt) >> 16) & 0xffff; setup.wLength = data_len; error = usb_pipe_ctrl_xfer_wait( wusbp->wusb_df_reg->dev_default_ph, &setup, &data, &cr, &cb_flags, 0); if (error != USB_SUCCESS) { USB_DPRINTF_L2(PRINT_MASK_ATTA, wusbp->wusb_df_log_hdl, "wusb_df_send_data: " "send failed rval=%d, cr=%d, cb=0x%x\n", error, cr, cb_flags); break; } } if (data) { freemsg(data); } return (error); }
/* * Allocate a TPI ACK reusing the old message if possible. */ mblk_t * tpi_ack_alloc(mblk_t *mp, size_t size, uchar_t db_type, t_scalar_t prim) { mblk_t *omp = mp; if ((mp = reallocb(mp, size, 0)) == NULL) { freemsg(omp); return (NULL); } if (mp->b_cont != NULL) { freemsg(mp->b_cont); mp->b_cont = NULL; } mp->b_datap->db_type = db_type; mp->b_wptr = mp->b_rptr + size; ((union T_primitives *)mp->b_rptr)->type = prim; return (mp); }
/* * DL_CAPABILITY_ACK/DL_ERROR_ACK */ static void proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) { dl_capability_ack_t *dlap; dl_capability_sub_t *dlsp; size_t subsize; dl_capab_dld_t dld; dl_capab_hcksum_t hcksum; dl_capab_zerocopy_t zcopy; dl_capab_vrrp_t vrrp; mac_capab_vrrp_t vrrp_capab; uint8_t *ptr; queue_t *q = dsp->ds_wq; mblk_t *mp1; boolean_t hcksum_capable = B_FALSE; boolean_t zcopy_capable = B_FALSE; boolean_t dld_capable = B_FALSE; boolean_t vrrp_capable = B_FALSE; /* * Initially assume no capabilities. */ subsize = 0; /* * Check if checksum offload is supported on this MAC. */ bzero(&hcksum, sizeof (dl_capab_hcksum_t)); if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_HCKSUM, &hcksum.hcksum_txflags)) { if (hcksum.hcksum_txflags != 0) { hcksum_capable = B_TRUE; subsize += sizeof (dl_capability_sub_t) + sizeof (dl_capab_hcksum_t); } } /* * Check if zerocopy is supported on this interface. * If advertising DL_CAPAB_ZEROCOPY has not been explicitly disabled * then reserve space for that capability. */ if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_ZCOPY, NULL) && !(dld_opt & DLD_OPT_NO_ZEROCOPY)) { zcopy_capable = B_TRUE; subsize += sizeof (dl_capability_sub_t) + sizeof (dl_capab_zerocopy_t); } /* * Direct capability negotiation interface between IP and DLD */ if (dsp->ds_sap == ETHERTYPE_IP && check_mod_above(dsp->ds_rq, "ip")) { dld_capable = B_TRUE; subsize += sizeof (dl_capability_sub_t) + sizeof (dl_capab_dld_t); } /* * Check if vrrp is supported on this interface. If so, reserve * space for that capability. */ if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_VRRP, &vrrp_capab)) { vrrp_capable = B_TRUE; subsize += sizeof (dl_capability_sub_t) + sizeof (dl_capab_vrrp_t); } /* * If there are no capabilities to advertise or if we * can't allocate a response, send a DL_ERROR_ACK. */ if ((mp1 = reallocb(mp, sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) { dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0); return; } mp = mp1; DB_TYPE(mp) = M_PROTO; mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize; bzero(mp->b_rptr, MBLKL(mp)); dlap = (dl_capability_ack_t *)mp->b_rptr; dlap->dl_primitive = DL_CAPABILITY_ACK; dlap->dl_sub_offset = sizeof (dl_capability_ack_t); dlap->dl_sub_length = subsize; ptr = (uint8_t *)&dlap[1]; /* * TCP/IP checksum offload. */ if (hcksum_capable) { dlsp = (dl_capability_sub_t *)ptr; dlsp->dl_cap = DL_CAPAB_HCKSUM; dlsp->dl_length = sizeof (dl_capab_hcksum_t); ptr += sizeof (dl_capability_sub_t); hcksum.hcksum_version = HCKSUM_VERSION_1; dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t)); ptr += sizeof (dl_capab_hcksum_t); } /* * Zero copy */ if (zcopy_capable) { dlsp = (dl_capability_sub_t *)ptr; dlsp->dl_cap = DL_CAPAB_ZEROCOPY; dlsp->dl_length = sizeof (dl_capab_zerocopy_t); ptr += sizeof (dl_capability_sub_t); bzero(&zcopy, sizeof (dl_capab_zerocopy_t)); zcopy.zerocopy_version = ZEROCOPY_VERSION_1; zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM; dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq); bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t)); ptr += sizeof (dl_capab_zerocopy_t); } /* * VRRP capability negotiation */ if (vrrp_capable) { dlsp = (dl_capability_sub_t *)ptr; dlsp->dl_cap = DL_CAPAB_VRRP; dlsp->dl_length = sizeof (dl_capab_vrrp_t); ptr += sizeof (dl_capability_sub_t); bzero(&vrrp, sizeof (dl_capab_vrrp_t)); vrrp.vrrp_af = vrrp_capab.mcv_af; bcopy(&vrrp, ptr, sizeof (dl_capab_vrrp_t)); ptr += sizeof (dl_capab_vrrp_t); } /* * Direct capability negotiation interface between IP and DLD. * Refer to dld.h for details. */ if (dld_capable) { dlsp = (dl_capability_sub_t *)ptr; dlsp->dl_cap = DL_CAPAB_DLD; dlsp->dl_length = sizeof (dl_capab_dld_t); ptr += sizeof (dl_capability_sub_t); bzero(&dld, sizeof (dl_capab_dld_t)); dld.dld_version = DLD_CURRENT_VERSION; dld.dld_capab = (uintptr_t)dld_capab; dld.dld_capab_handle = (uintptr_t)dsp; dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq); bcopy(&dld, ptr, sizeof (dl_capab_dld_t)); ptr += sizeof (dl_capab_dld_t); } ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize); qreply(q, mp); }