int scsi_is_ready(struct disk_op_s *op) { dprintf(6, "scsi_is_ready (drive=%p)\n", op->drive_g); /* Retry TEST UNIT READY for 5 seconds unless MEDIUM NOT PRESENT is * reported by the device. If the device reports "IN PROGRESS", * 30 seconds is added. */ int in_progress = 0; u64 end = calc_future_tsc(5000); for (;;) { if (check_tsc(end)) { dprintf(1, "test unit ready failed\n"); return -1; } int ret = cdb_test_unit_ready(op); if (!ret) // Success break; struct cdbres_request_sense sense; ret = cdb_get_sense(op, &sense); if (ret) // Error - retry. continue; // Sense succeeded. if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */ dprintf(1, "Device reports MEDIUM NOT PRESENT\n"); return -1; } if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) { /* IN PROGRESS OF BECOMING READY */ printf("Waiting for device to detect medium... "); /* Allow 30 seconds more */ end = calc_future_tsc(30000); in_progress = 1; } } return 0; }
// Reset device on port static int usb_hub_reset(struct usbhub_s *hub, u32 port) { int ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET); if (ret) goto fail; // Wait for reset to complete. struct usb_port_status sts; u64 end = calc_future_tsc(USB_TIME_DRST * 2); for (;;) { ret = get_port_status(hub, port, &sts); if (ret) goto fail; if (!(sts.wPortStatus & USB_PORT_STAT_RESET)) break; if (check_tsc(end)) { warn_timeout(); goto fail; } msleep(5); } // Reset complete. if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION)) // Device no longer present return -1; return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK) >> USB_PORT_STAT_SPEED_SHIFT); fail: dprintf(1, "Failure on hub port %d reset\n", port); usb_hub_disconnect(hub, port); return -1; }
static void configure_ehci(void *data) { struct usb_ehci_s *cntl = data; // Allocate ram for schedule storage struct ehci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl)); struct ehci_qh *intr_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*intr_qh)); struct ehci_qh *async_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*async_qh)); if (!fl || !intr_qh || !async_qh) { warn_noalloc(); goto fail; } // XXX - check for halted? // Reset the HC u32 cmd = readl(&cntl->regs->usbcmd); writel(&cntl->regs->usbcmd, (cmd & ~(CMD_ASE | CMD_PSE)) | CMD_HCRESET); u64 end = calc_future_tsc(250); for (;;) { cmd = readl(&cntl->regs->usbcmd); if (!(cmd & CMD_HCRESET)) break; if (check_tsc(end)) { warn_timeout(); goto fail; } yield(); } // Disable interrupts (just to be safe). writel(&cntl->regs->usbintr, 0); // Set schedule to point to primary intr queue head memset(intr_qh, 0, sizeof(*intr_qh)); intr_qh->next = EHCI_PTR_TERM; intr_qh->info2 = (0x01 << QH_SMASK_SHIFT); intr_qh->token = QTD_STS_HALT; intr_qh->qtd_next = intr_qh->alt_next = EHCI_PTR_TERM; int i; for (i=0; i<ARRAY_SIZE(fl->links); i++) fl->links[i] = (u32)intr_qh | EHCI_PTR_QH; writel(&cntl->regs->periodiclistbase, (u32)fl); // Set async list to point to primary async queue head memset(async_qh, 0, sizeof(*async_qh)); async_qh->next = (u32)async_qh | EHCI_PTR_QH; async_qh->info1 = QH_HEAD; async_qh->token = QTD_STS_HALT; async_qh->qtd_next = async_qh->alt_next = EHCI_PTR_TERM; cntl->async_qh = async_qh; writel(&cntl->regs->asynclistbase, (u32)async_qh); // Enable queues writel(&cntl->regs->usbcmd, cmd | CMD_ASE | CMD_PSE | CMD_RUN); // Set default of high speed for root hub. writel(&cntl->regs->configflag, 1); cntl->checkports = readl(&cntl->caps->hcsparams) & HCS_N_PORTS_MASK; // Find devices int count = check_ehci_ports(cntl); ehci_free_pipes(cntl); if (count) // Success return; // No devices found - shutdown and free controller. writel(&cntl->regs->usbcmd, cmd & ~CMD_RUN); msleep(4); // 2ms to stop reading memory - XXX fail: free(fl); free(intr_qh); free(async_qh); free(cntl); }