📄 qlogicisp.c
字号:
isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR); if ((isp_inw(host, PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) { status = isp_inw(host, MBOX0); DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n", status)); switch (status) { case ASYNC_SCSI_BUS_RESET: case EXECUTION_TIMEOUT_RESET: hostdata->send_marker = 1; break; case INVALID_COMMAND: case HOST_INTERFACE_ERROR: case COMMAND_ERROR: case COMMAND_PARAM_ERROR: printk("qlogicisp : bad mailbox return status\n"); break; } isp_outw(0x0, host, PCI_SEMAPHORE); } out_ptr = hostdata->res_out_ptr; DEBUG_INTR(printk("qlogicisp : response queue update\n")); DEBUG_INTR(printk("qlogicisp : response queue depth %d\n", QUEUE_DEPTH(in_ptr, out_ptr, RES_QUEUE_LEN))); while (out_ptr != in_ptr) { u_int cmd_slot; sts = (struct Status_Entry *) &hostdata->res_cpu[out_ptr]; out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; cmd_slot = sts->handle; Cmnd = hostdata->cmd_slots[cmd_slot]; hostdata->cmd_slots[cmd_slot] = NULL; TRACE("done", out_ptr, Cmnd); if (le16_to_cpu(sts->completion_status) == CS_RESET_OCCURRED || le16_to_cpu(sts->completion_status) == CS_ABORTED || (le16_to_cpu(sts->status_flags) & STF_BUS_RESET)) hostdata->send_marker = 1; if (le16_to_cpu(sts->state_flags) & SF_GOT_SENSE) memcpy(Cmnd->sense_buffer, sts->req_sense_data, sizeof(Cmnd->sense_buffer)); DEBUG_INTR(isp1020_print_status_entry(sts)); if (sts->hdr.entry_type == ENTRY_STATUS) Cmnd->result = isp1020_return_status(sts); else Cmnd->result = DID_ERROR << 16; if (Cmnd->use_sg) pci_unmap_sg(hostdata->pci_dev, (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); else if (Cmnd->request_bufflen) pci_unmap_single(hostdata->pci_dev,#ifdef CONFIG_QL_ISP_A64 (dma_addr_t)((long)Cmnd->SCp.ptr),#else (u32)((long)Cmnd->SCp.ptr),#endif Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); isp_outw(out_ptr, host, MBOX5); (*Cmnd->scsi_done)(Cmnd); } hostdata->res_out_ptr = out_ptr; LEAVE_INTR("isp1020_intr_handler");}static int isp1020_return_status(struct Status_Entry *sts){ int host_status = DID_ERROR;#if DEBUG_ISP1020_INTR static char *reason[] = { "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR" };#endif /* DEBUG_ISP1020_INTR */ ENTER("isp1020_return_status"); DEBUG(printk("qlogicisp : completion status = 0x%04x\n", le16_to_cpu(sts->completion_status))); switch(le16_to_cpu(sts->completion_status)) { case CS_COMPLETE: host_status = DID_OK; break; case CS_INCOMPLETE: if (!(le16_to_cpu(sts->state_flags) & SF_GOT_BUS)) host_status = DID_NO_CONNECT; else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_TARGET)) host_status = DID_BAD_TARGET; else if (!(le16_to_cpu(sts->state_flags) & SF_SENT_CDB)) host_status = DID_ERROR; else if (!(le16_to_cpu(sts->state_flags) & SF_TRANSFERRED_DATA)) host_status = DID_ERROR; else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_STATUS)) host_status = DID_ERROR; else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_SENSE)) host_status = DID_ERROR; break; case CS_DMA_ERROR: case CS_TRANSPORT_ERROR: host_status = DID_ERROR; break; case CS_RESET_OCCURRED: host_status = DID_RESET; break; case CS_ABORTED: host_status = DID_ABORT; break; case CS_TIMEOUT: host_status = DID_TIME_OUT; break; case CS_DATA_OVERRUN: case CS_COMMAND_OVERRUN: case CS_STATUS_OVERRUN: case CS_BAD_MESSAGE: case CS_NO_MESSAGE_OUT: case CS_EXT_ID_FAILED: case CS_IDE_MSG_FAILED: case CS_ABORT_MSG_FAILED: case CS_NOP_MSG_FAILED: case CS_PARITY_ERROR_MSG_FAILED: case CS_DEVICE_RESET_MSG_FAILED: case CS_ID_MSG_FAILED: case CS_UNEXP_BUS_FREE: host_status = DID_ERROR; break; case CS_DATA_UNDERRUN: host_status = DID_OK; break; default: printk("qlogicisp : unknown completion status 0x%04x\n", le16_to_cpu(sts->completion_status)); host_status = DID_ERROR; break; } DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n", reason[host_status], le16_to_cpu(sts->scsi_status))); LEAVE("isp1020_return_status"); return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16);}int isp1020_abort(Scsi_Cmnd *Cmnd){ u_short param[6]; struct Scsi_Host *host; struct isp1020_hostdata *hostdata; int return_status = SCSI_ABORT_SUCCESS; u_int cmd_cookie; int i; ENTER("isp1020_abort"); host = Cmnd->host; hostdata = (struct isp1020_hostdata *) host->hostdata; for (i = 0; i < QLOGICISP_REQ_QUEUE_LEN + 1; i++) if (hostdata->cmd_slots[i] == Cmnd) break; cmd_cookie = i; isp1020_disable_irqs(host); param[0] = MBOX_ABORT; param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; param[2] = cmd_cookie >> 16; param[3] = cmd_cookie & 0xffff; isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicisp : scsi abort failure: %x\n", param[0]); return_status = SCSI_ABORT_ERROR; } isp1020_enable_irqs(host); LEAVE("isp1020_abort"); return return_status;}int isp1020_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags){ u_short param[6]; struct Scsi_Host *host; struct isp1020_hostdata *hostdata; int return_status = SCSI_RESET_SUCCESS; ENTER("isp1020_reset"); host = Cmnd->host; hostdata = (struct isp1020_hostdata *) host->hostdata; param[0] = MBOX_BUS_RESET; param[1] = hostdata->host_param.bus_reset_delay; isp1020_disable_irqs(host); isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicisp : scsi bus reset failure: %x\n", param[0]); return_status = SCSI_RESET_ERROR; } isp1020_enable_irqs(host); LEAVE("isp1020_reset"); return return_status;;}int isp1020_biosparam(Disk *disk, kdev_t n, int ip[]){ int size = disk->capacity; ENTER("isp1020_biosparam"); ip[0] = 64; ip[1] = 32; ip[2] = size >> 11; if (ip[2] > 1024) { ip[0] = 255; ip[1] = 63; ip[2] = size / (ip[0] * ip[1]);#if 0 if (ip[2] > 1023) ip[2] = 1023;#endif } LEAVE("isp1020_biosparam"); return 0;}static int isp1020_reset_hardware(struct Scsi_Host *host){ u_short param[6]; int loop_count; ENTER("isp1020_reset_hardware"); isp_outw(ISP_RESET, host, PCI_INTF_CTL); udelay(100); isp_outw(HCCR_RESET, host, HOST_HCCR); udelay(100); isp_outw(HCCR_RELEASE, host, HOST_HCCR); isp_outw(HCCR_BIOS_DISABLE, host, HOST_HCCR); loop_count = DEFAULT_LOOP_COUNT; while (--loop_count && isp_inw(host, HOST_HCCR) == RISC_BUSY) barrier(); if (!loop_count) printk("qlogicisp: reset_hardware loop timeout\n"); isp_outw(0, host, ISP_CFG1);#if DEBUG_ISP1020 printk("qlogicisp : mbox 0 0x%04x \n", isp_inw(host, MBOX0)); printk("qlogicisp : mbox 1 0x%04x \n", isp_inw(host, MBOX1)); printk("qlogicisp : mbox 2 0x%04x \n", isp_inw(host, MBOX2)); printk("qlogicisp : mbox 3 0x%04x \n", isp_inw(host, MBOX3)); printk("qlogicisp : mbox 4 0x%04x \n", isp_inw(host, MBOX4)); printk("qlogicisp : mbox 5 0x%04x \n", isp_inw(host, MBOX5));#endif /* DEBUG_ISP1020 */ param[0] = MBOX_NO_OP; isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicisp : NOP test failed\n"); return 1; } DEBUG(printk("qlogicisp : loading risc ram\n"));#if RELOAD_FIRMWARE for (loop_count = 0; loop_count < risc_code_length01; loop_count++) { param[0] = MBOX_WRITE_RAM_WORD; param[1] = risc_code_addr01 + loop_count; param[2] = risc_code01[loop_count]; isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicisp : firmware load failure at %d\n", loop_count); return 1; } }#endif /* RELOAD_FIRMWARE */ DEBUG(printk("qlogicisp : verifying checksum\n")); param[0] = MBOX_VERIFY_CHECKSUM; param[1] = risc_code_addr01; isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicisp : ram checksum failure\n"); return 1; } DEBUG(printk("qlogicisp : executing firmware\n")); param[0] = MBOX_EXEC_FIRMWARE; param[1] = risc_code_addr01; isp1020_mbox_command(host, param); param[0] = MBOX_ABOUT_FIRMWARE; isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicisp : about firmware failure\n"); return 1; } DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1])); DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2])); LEAVE("isp1020_reset_hardware"); return 0;}static int isp1020_init(struct Scsi_Host *sh){ u_long io_base, mem_base, io_flags, mem_flags; struct isp1020_hostdata *hostdata; u_char revision; u_int irq; u_short command; struct pci_dev *pdev; ENTER("isp1020_init"); hostdata = (struct isp1020_hostdata *) sh->hostdata; pdev = hostdata->pci_dev; if (pci_read_config_word(pdev, PCI_COMMAND, &command) || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision)) { printk("qlogicisp : error reading PCI configuration\n"); return 1; } io_base = pci_resource_start(pdev, 0); mem_base = pci_resource_start(pdev, 1); io_flags = pci_resource_flags(pdev, 0); mem_flags = pci_resource_flags(pdev, 1); irq = pdev->irq; if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) { printk("qlogicisp : 0x%04x is not QLogic vendor ID\n", pdev->vendor); return 1; } if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP1020) { printk("qlogicisp : 0x%04x does not match ISP1020 device id\n", pdev->device); return 1; }#ifdef __alpha__ /* Force ALPHA to use bus I/O and not bus MEM. This is to avoid having to use HAE_MEM registers, which is broken on some platforms and with SMP. */ command &= ~PCI_COMMAND_MEMORY; #endif if (!(command & PCI_COMMAND_MASTER)) { printk("qlogicisp : bus mastering is disabled\n"); return 1; } sh->io_port = io_base; if (check_region(sh->io_port, 0xff)) { printk("qlogicisp : i/o region 0x%lx-0x%lx already " "in use\n", sh->io_port, sh->io_port + 0xff); return 1; } request_region(sh->io_port, 0xff, "qlogicisp"); if ((command & PCI_COMMAND_MEMORY) && ((mem_flags & 1) == 0)) { mem_base = (u_long) ioremap(mem_base, PAGE_SIZE); hostdata->memaddr = mem_base; } else { if (command & PCI_COMMAND_IO && (io_flags & 3) != 1) { printk("qlogicisp : i/o mapping is disabled\n"); release_region(sh->io_port, 0xff); return 1; } hostdata->memaddr = 0; /* zero to signify no i/o mapping */ mem_base = 0; } if (revision != ISP1020_REV_ID) printk("qlogicisp : new isp1020 revision ID (%d)\n", revision); if (isp_inw(sh, PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC || isp_inw(sh, PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020) { printk("qlogicisp : can't decode %s address space 0x%lx\n", (io_base ? "I/O" : "MEM"), (io_base ? io_base : mem_base)); iounmap((void *)hostdata->memaddr); release_region(sh->io_port, 0xff); return 1; } hostdata->revision = revision; sh->irq = irq; sh->max_id = MAX_TARGETS; sh->max_lun = MAX_LUNS; hostdata->res_cpu = pci_alloc_consistent(hostdata->pci_dev, QSIZE(RES_QUEUE_LEN), &hostdata->res_dma); if (hostdata->res_cpu == NULL) { printk("qlogicisp : can't allocate response queue\n"); return 1; } hostdata->req_cpu = pci_alloc_consistent(hostdata->pci_dev, QSIZE(QLOGICISP_REQ_QUEUE_LEN), &hostdata->req_dma); if (hostdata->req_cpu == NULL) { pci_free_consistent(hostdata->pci_dev, QSIZE(RES_QUEUE_LEN), hostdata->res_cpu, hostdata->res_dma); printk("qlogicisp : can't allocate request queue\n"); return 1; } LEAVE("isp1020_init"); return 0;}#if USE_NVRAM_DEFAULTSstatic int isp1020_get_defaults(struct Scsi_Host *host){ int i; u_short value; struct isp1020_hostdata *hostdata = (struct isp1020_hostdata *) host->hostdata; ENTER("isp1020_get_defaults"); if (!isp1020_verify_nvram(host)) { printk("qlogicisp : nvram checksum failure\n"); printk("qlogicisp : attempting to use default parameters\n"); return isp1020_set_defaults(host); } value = isp1020_read_nvram_word(host, 2); hostdata->host_param.fifo_threshold = (value >> 8) & 0x03;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -