static int usb_stor_BBB_reset(struct us_data *us) { int result; unsigned int pipe; /* * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class) * * For Reset Recovery the host shall issue in the following order: * a) a Bulk-Only Mass Storage Reset * b) a Clear Feature HALT to the Bulk-In endpoint * c) a Clear Feature HALT to the Bulk-Out endpoint * * This is done in 3 steps. * * If the reset doesn't succeed, the device should be port reset. * * This comment stolen from FreeBSD's /sys/dev/usb/umass.c. */ debug("BBB_reset\n"); result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), US_BBB_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, NULL, 0, USB_CNTL_TIMEOUT * 5); if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { debug("RESET:stall\n"); return -1; } /* long wait for reset */ _mdelay(150); debug("BBB_reset result %d: status %lX reset\n", result, us->pusb_dev->status); pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); result = usb_clear_halt(us->pusb_dev, pipe); /* long wait for reset */ _mdelay(150); debug("BBB_reset result %d: status %lX clearing IN endpoint\n", result, us->pusb_dev->status); /* long wait for reset */ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); result = usb_clear_halt(us->pusb_dev, pipe); _mdelay(150); debug("BBB_reset result %d: status %lX clearing OUT endpoint\n", result, us->pusb_dev->status); debug("BBB_reset done\n"); return 0; }
/* FIXME: this reset function doesn't really reset the port, and it * should. Actually it should probably do what it's doing here, and * reset the port physically */ static int usb_stor_CB_reset(struct us_data *us) { unsigned char cmd[12]; int result; debug("CB_reset\n"); memset(cmd, 0xff, sizeof(cmd)); cmd[0] = SCSI_SEND_DIAG; cmd[1] = 4; result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, cmd, sizeof(cmd), USB_CNTL_TIMEOUT * 5); /* long wait for reset */ _mdelay(1500); debug("CB_reset result %d: status %lX clearing endpoint halt\n", result, us->pusb_dev->status); usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); debug("CB_reset done\n"); return 0; }
void mdelay(uint32_t ms) { if (ms == 0) { return; } while (ms--) { _mdelay(); } }
static int usb_stor_CBI_get_status(ccb *srb, struct us_data *us) { int timeout; us->ip_wanted = 1; submit_int_msg(us->pusb_dev, us->irqpipe, (void *) &us->ip_data, us->irqmaxp, us->irqinterval); timeout = 1000; while (timeout--) { if ((volatile int *)(unsigned long long)us->ip_wanted == NULL) break; _mdelay(10); } if (us->ip_wanted) { printf(" Did not get interrupt on CBI\n"); us->ip_wanted = 0; return USB_STOR_TRANSPORT_ERROR; } debug("Got interrupt data 0x%x, transfered %d status 0x%lX\n", us->ip_data, us->pusb_dev->irq_act_len, us->pusb_dev->irq_status); /* UFI gives us ASC and ASCQ, like a request sense */ if (us->subclass == US_SC_UFI) { if (srb->cmd[0] == SCSI_REQ_SENSE || srb->cmd[0] == SCSI_INQUIRY) return USB_STOR_TRANSPORT_GOOD; /* Good */ else if (us->ip_data) return USB_STOR_TRANSPORT_FAILED; else return USB_STOR_TRANSPORT_GOOD; } /* otherwise, we interpret the data normally */ switch (us->ip_data) { case 0x0001: return USB_STOR_TRANSPORT_GOOD; case 0x0002: return USB_STOR_TRANSPORT_FAILED; default: return USB_STOR_TRANSPORT_ERROR; } /* switch */ return USB_STOR_TRANSPORT_ERROR; }
/** * Low level initialize the Octeon PCI controller * * @return */ static inline void octeon_pci_initialize(void) { int64_t stat; octeon_pci_cfg01_t cfg01; octeon_npi_ctl_status_t ctl_status; octeon_pci_ctl_status_2_t ctl_status_2; octeon_pci_cfg19_t cfg19; octeon_pci_cfg16_t cfg16; octeon_pci_cfg22_t cfg22; octeon_pci_cfg56_t cfg56; /* Reset the PCI Bus */ octeon_write_csr(OCTEON_CIU_SOFT_PRST, 0x1); stat = octeon_read_csr(OCTEON_CIU_SOFT_PRST); _mdelay(2); /* Hold PCI reset for 2 ms */ ctl_status.u64 = 0; ctl_status.s.max_word = 1; ctl_status.s.timer = 1; octeon_write_csr(OCTEON_NPI_CTL_STATUS, ctl_status.u64); /* Deassert PCI reset and advertize PCX Host Mode Device Capability (64b) */ octeon_write_csr(OCTEON_CIU_SOFT_PRST, 0x4); stat = octeon_read_csr(OCTEON_CIU_SOFT_PRST); _mdelay(2); /* Wait 2 ms after deasserting PCI reset */ ctl_status_2.u32 = 0; ctl_status_2.s.bar2pres = 1; /* bar2 present */ ctl_status_2.s.bar2_enb = 1; /* bar2 enable */ ctl_status_2.s.tsr_hwm = 1; /* Initializes to 0. Must be set before any PCI reads. */ npi_write32(OCTEON_NPI_PCI_CTL_STATUS_2, ctl_status_2.u32); _mdelay(4); /* Wait 2 ms before doing PCI reads */ ctl_status_2.u32 = npi_read32(OCTEON_NPI_PCI_CTL_STATUS_2); printk("PCI Status: %s %s-bit\n", ctl_status_2.s.ap_pcix ? "PCI-X" : "PCI", ctl_status_2.s.ap_64ad ? "64" : "32"); /* ** TDOMC must be set to one in PCI mode. TDOMC should be set to 4 ** in PCI-X mode to allow four oustanding splits. Otherwise, ** should not change from its reset value. Don't write PCI_CFG19 ** in PCI mode (0x82000001 reset value), write it to 0x82000004 ** after PCI-X mode is known. MRBCI,MDWE,MDRE -> must be zero. ** MRBCM -> must be one. */ if (ctl_status_2.s.ap_pcix) { cfg19.u32 = 0; cfg19.s.tdomc = 4; /* Target Delayed/Split request outstanding maximum count. [1..31] and 0=32. NOTE: If the user programs these bits beyond the Designed Maximum outstanding count, then the designed maximum table depth will be used instead. No additional Deferred/Split transactions will be accepted if this outstanding maximum count is reached. Furthermore, no additional deferred/split transactions will be accepted if the I/O delay/ I/O Split Request outstanding maximum is reached. */ cfg19.s.mdrrmc = 2; /* Master Deferred Read Request Outstanding Max Count (PCI only). CR4C[26:24] Max SAC cycles MAX DAC cycles 000 8 4 001 1 0 010 2 1 011 3 1 100 4 2 101 5 2 110 6 3 111 7 3 For example, if these bits are programmed to 100, the core can support 2 DAC cycles, 4 SAC cycles or a combination of 1 DAC and 2 SAC cycles. NOTE: For the PCI-X maximum outstanding split transactions, refer to CRE0[22:20] */ cfg19.s.mrbcm = 1; /* Master Request (Memory Read) Byte Count/Byte Enable select. 0 = Byte Enables valid. In PCI mode, a burst transaction cannot be performed using Memory Read command=4?h6. 1 = DWORD Byte Count valid (default). In PCI Mode, the memory read byte enables are automatically generated by the core. Note: N3 Master Request transaction sizes are always determined through the am_attr[<35:32>|<7:0>] field. */ npi_write32(OCTEON_NPI_PCI_CFG19, cfg19.u32); } cfg01.u32 = 0; cfg01.s.msae = 1; /* Memory Space Access Enable */ cfg01.s.me = 1; /* Master Enable */ cfg01.s.pee = 1; /* PERR# Enable */ cfg01.s.see = 1; /* System Error Enable */ cfg01.s.fbbe = 1; /* Fast Back to Back Transaction Enable */ npi_write32(OCTEON_NPI_PCI_CFG01, cfg01.u32); npi_read32(OCTEON_NPI_PCI_CFG01); #ifdef USE_OCTEON_INTERNAL_ARBITER /* ** When OCTEON is a PCI host, most systems will use OCTEON's ** internal arbiter, so must enable it before any PCI/PCI-X ** traffic can occur. */ { octeon_npi_pci_int_arb_cfg_t pci_int_arb_cfg; pci_int_arb_cfg.u64 = 0; pci_int_arb_cfg.s.en = 1; /* Internal arbiter enable */ octeon_write_csr(OCTEON_NPI_PCI_INT_ARB_CFG, pci_int_arb_cfg.u64); } #endif /* USE_OCTEON_INTERNAL_ARBITER */ /* ** Preferrably written to 1 to set MLTD. [RDSATI,TRTAE, ** TWTAE,TMAE,DPPMR -> must be zero. TILT -> must not be set to ** 1..7. */ cfg16.u32 = 0; cfg16.s.mltd = 1; /* Master Latency Timer Disable */ npi_write32(OCTEON_NPI_PCI_CFG16, cfg16.u32); /* ** Should be written to 0x4ff00. MTTV -> must be zero. ** FLUSH -> must be 1. MRV -> should be 0xFF. */ cfg22.u32 = 0; cfg22.s.mrv = 0xff; /* Master Retry Value [1..255] and 0=infinite */ cfg22.s.flush = 1; /* AM_DO_FLUSH_I control NOTE: This bit MUST BE ONE for proper N3K operation */ npi_write32(OCTEON_NPI_PCI_CFG22, cfg22.u32); /* ** MOST Indicates the maximum number of outstanding splits (in -1 ** notation) when OCTEON is in PCI-X mode. PCI-X performance is ** affected by the MOST selection. Should generally be written ** with one of 0x3be807, 0x2be807, 0x1be807, or 0x0be807, ** depending on the desired MOST of 3, 2, 1, or 0, respectively. */ cfg56.u32 = 0; cfg56.s.pxcid = 7; /* RO - PCI-X Capability ID */ cfg56.s.ncp = 0xe8; /* RO - Next Capability Pointer */ cfg56.s.dpere = 1; /* Data Parity Error Recovery Enable */ cfg56.s.roe = 1; /* Relaxed Ordering Enable */ cfg56.s.mmbc = 1; /* Maximum Memory Byte Count [0=512B,1=1024B,2=2048B,3=4096B] */ cfg56.s.most = 3; /* Maximum outstanding Split transactions [0=1 .. 7=32] */ npi_write32(OCTEON_NPI_PCI_CFG56, cfg56.u32); /* ** Affects PCI performance when OCTEON services reads to its ** BAR1/BAR2. Refer to Section 10.6.1. The recommended values are ** 0x22, 0x33, and 0x33 for PCI_READ_CMD_6, PCI_READ_CMD_C, and ** PCI_READ_CMD_E, respectively. Note that these values differ ** from their reset values. */ npi_write32(OCTEON_NPI_PCI_READ_CMD_6, 0x22); npi_write32(OCTEON_NPI_PCI_READ_CMD_C, 0x33); npi_write32(OCTEON_NPI_PCI_READ_CMD_E, 0x33); }
static int usb_stor_BBB_transport(ccb *srb, struct us_data *us) { int result, retry; int dir_in; int actlen, data_actlen; unsigned int pipe, pipein, pipeout; ALLOC_CACHE_ALIGN_BUFFER(umass_bbb_csw_t, csw, 1); #ifdef BBB_XPORT_TRACE unsigned char *ptr; int index; #endif if (us->pusb_dev->connect_status == 0) return -1; dir_in = US_DIRECTION(srb->cmd[0]); /* COMMAND phase */ debug("COMMAND phase\n"); result = usb_stor_BBB_comdat(srb, us); if (result < 0) { debug("failed to send CBW status %ld\n", us->pusb_dev->status); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } if (!(us->flags & USB_READY)) _mdelay(5); pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* DATA phase + error handling */ data_actlen = 0; /* no data, go immediately to the STATUS phase */ if (srb->datalen == 0) goto st; debug("DATA phase\n"); if (dir_in) pipe = pipein; else pipe = pipeout; result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT * 5); /* special handling of STALL in DATA phase */ if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { debug("DATA:stall\n"); /* clear the STALL on the endpoint */ result = usb_stor_BBB_clear_endpt_stall(us, dir_in ? us->ep_in : us->ep_out); if (result >= 0) /* continue on to STATUS phase */ goto st; } if (result < 0) { debug("usb_bulk_msg error status %ld\n", us->pusb_dev->status); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } #ifdef BBB_XPORT_TRACE for (index = 0; index < data_actlen; index++) printf("pdata[%d] %#x ", index, srb->pdata[index]); printf("\n"); #endif /* STATUS phase + error handling */ st: retry = 0; again: debug("STATUS phase\n"); result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); /* special handling of STALL in STATUS phase */ if ((result < 0) && (retry < 1) && (us->pusb_dev->status & USB_ST_STALLED)) { debug("STATUS:stall\n"); /* clear the STALL on the endpoint */ result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in); if (result >= 0 && (retry++ < 1)) /* do a retry */ goto again; } if (result < 0) { debug("usb_bulk_msg error status %ld\n", us->pusb_dev->status); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } #ifdef BBB_XPORT_TRACE ptr = (unsigned char *)csw; for (index = 0; index < UMASS_BBB_CSW_SIZE; index++) printf("ptr[%d] %#x ", index, ptr[index]); printf("\n"); #endif /* misuse pipe to get the residue */ pipe = le32_to_cpu(csw->dCSWDataResidue); if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0) pipe = srb->datalen - data_actlen; if (CSWSIGNATURE != le32_to_cpu(csw->dCSWSignature)) { debug("!CSWSIGNATURE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if ((CBWTag - 1) != le32_to_cpu(csw->dCSWTag)) { debug("!Tag\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (csw->bCSWStatus > CSWSTATUS_PHASE) { debug(">PHASE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (csw->bCSWStatus == CSWSTATUS_PHASE) { debug("=PHASE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (data_actlen > srb->datalen) { debug("transferred %dB instead of %ldB\n", data_actlen, srb->datalen); return USB_STOR_TRANSPORT_FAILED; } else if (csw->bCSWStatus == CSWSTATUS_FAILED) { debug("FAILED\n"); return USB_STOR_TRANSPORT_FAILED; } return result; }