📄 qlogicisp.c
字号:
PACKB(6, 6), /* MBOX_MAILBOX_REG_TEST */ PACKB(2, 3), /* MBOX_VERIFY_CHECKSUM */ PACKB(1, 3), /* MBOX_ABOUT_FIRMWARE */ PACKB(0, 0), /* 0x0009 */ PACKB(0, 0), /* 0x000a */ PACKB(0, 0), /* 0x000b */ PACKB(0, 0), /* 0x000c */ PACKB(0, 0), /* 0x000d */ PACKB(1, 2), /* MBOX_CHECK_FIRMWARE */ PACKB(0, 0), /* 0x000f */ PACKB(5, 5), /* MBOX_INIT_REQ_QUEUE */ PACKB(6, 6), /* MBOX_INIT_RES_QUEUE */ PACKB(4, 4), /* MBOX_EXECUTE_IOCB */ PACKB(2, 2), /* MBOX_WAKE_UP */ PACKB(1, 6), /* MBOX_STOP_FIRMWARE */ PACKB(4, 4), /* MBOX_ABORT */ PACKB(2, 2), /* MBOX_ABORT_DEVICE */ PACKB(3, 3), /* MBOX_ABORT_TARGET */ PACKB(2, 2), /* MBOX_BUS_RESET */ PACKB(2, 3), /* MBOX_STOP_QUEUE */ PACKB(2, 3), /* MBOX_START_QUEUE */ PACKB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */ PACKB(2, 3), /* MBOX_ABORT_QUEUE */ PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */ PACKB(0, 0), /* 0x001e */ PACKB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */ PACKB(1, 2), /* MBOX_GET_INIT_SCSI_ID */ PACKB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */ PACKB(1, 3), /* MBOX_GET_RETRY_COUNT */ PACKB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */ PACKB(1, 2), /* MBOX_GET_CLOCK_RATE */ PACKB(1, 2), /* MBOX_GET_ACT_NEG_STATE */ PACKB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */ PACKB(1, 3), /* MBOX_GET_PCI_PARAMS */ PACKB(2, 4), /* MBOX_GET_TARGET_PARAMS */ PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */ PACKB(0, 0), /* 0x002a */ PACKB(0, 0), /* 0x002b */ PACKB(0, 0), /* 0x002c */ PACKB(0, 0), /* 0x002d */ PACKB(0, 0), /* 0x002e */ PACKB(0, 0), /* 0x002f */ PACKB(2, 2), /* MBOX_SET_INIT_SCSI_ID */ PACKB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */ PACKB(3, 3), /* MBOX_SET_RETRY_COUNT */ PACKB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */ PACKB(2, 2), /* MBOX_SET_CLOCK_RATE */ PACKB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */ PACKB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */ PACKB(3, 3), /* MBOX_SET_PCI_CONTROL_PARAMS */ PACKB(4, 4), /* MBOX_SET_TARGET_PARAMS */ PACKB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */ PACKB(0, 0), /* 0x003a */ PACKB(0, 0), /* 0x003b */ PACKB(0, 0), /* 0x003c */ PACKB(0, 0), /* 0x003d */ PACKB(0, 0), /* 0x003e */ PACKB(0, 0), /* 0x003f */ PACKB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */ PACKB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */ PACKB(2, 3) /* MBOX_EXEC_BIOS_IOCB */};#define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short))struct host_param { u_short fifo_threshold; u_short host_adapter_enable; u_short initiator_scsi_id; u_short bus_reset_delay; u_short retry_count; u_short retry_delay; u_short async_data_setup_time; u_short req_ack_active_negation; u_short data_line_active_negation; u_short data_dma_burst_enable; u_short command_dma_burst_enable; u_short tag_aging; u_short selection_timeout; u_short max_queue_depth;};/* * Device Flags: * * Bit Name * --------- * 7 Disconnect Privilege * 6 Parity Checking * 5 Wide Data Transfers * 4 Synchronous Data Transfers * 3 Tagged Queuing * 2 Automatic Request Sense * 1 Stop Queue on Check Condition * 0 Renegotiate on Error */struct dev_param { u_short device_flags; u_short execution_throttle; u_short synchronous_period; u_short synchronous_offset; u_short device_enable; u_short reserved; /* pad */};/* * The result queue can be quite a bit smaller since continuation entries * do not show up there: */#define RES_QUEUE_LEN ((QLOGICISP_REQ_QUEUE_LEN + 1) / 8 - 1)#define QUEUE_ENTRY_LEN 64struct isp1020_hostdata { u_char bus; u_char revision; u_char device_fn; struct host_param host_param; struct dev_param dev_param[MAX_TARGETS]; /* result and request queues (shared with isp1020): */ u_int req_in_ptr; /* index of next request slot */ u_int res_out_ptr; /* index of next result slot */ /* this is here so the queues are nicely aligned */ long send_marker; /* do we need to send a marker? */ char res[RES_QUEUE_LEN+1][QUEUE_ENTRY_LEN]; char req[QLOGICISP_REQ_QUEUE_LEN+1][QUEUE_ENTRY_LEN];};/* queue length's _must_ be power of two: */#define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql))#define REQ_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, \ QLOGICISP_REQ_QUEUE_LEN)#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN)struct Scsi_Host *irq2host[NR_IRQS];static void isp1020_enable_irqs(struct Scsi_Host *);static void isp1020_disable_irqs(struct Scsi_Host *);static int isp1020_init(struct Scsi_Host *);static int isp1020_reset_hardware(struct Scsi_Host *);static int isp1020_set_defaults(struct Scsi_Host *);static int isp1020_load_parameters(struct Scsi_Host *);static int isp1020_mbox_command(struct Scsi_Host *, u_short []); static int isp1020_return_status(struct Status_Entry *);static void isp1020_intr_handler(int, void *, struct pt_regs *);#if USE_NVRAM_DEFAULTSstatic int isp1020_get_defaults(struct Scsi_Host *);static int isp1020_verify_nvram(struct Scsi_Host *);static u_short isp1020_read_nvram_word(struct Scsi_Host *, u_short);#endif#if DEBUG_ISP1020static void isp1020_print_scsi_cmd(Scsi_Cmnd *);#endif#if DEBUG_ISP1020_INTRstatic void isp1020_print_status_entry(struct Status_Entry *);#endifstatic struct proc_dir_entry proc_scsi_isp1020 = { PROC_SCSI_QLOGICISP, 7, "isp1020", S_IFDIR | S_IRUGO | S_IXUGO, 2};static inline void isp1020_enable_irqs(struct Scsi_Host *host){ outw(ISP_EN_INT|ISP_EN_RISC, host->io_port + PCI_INTF_CTL);}static inline void isp1020_disable_irqs(struct Scsi_Host *host){ outw(0x0, host->io_port + PCI_INTF_CTL);}int isp1020_detect(Scsi_Host_Template *tmpt){ int hosts = 0; u_short index; u_char bus, device_fn; struct Scsi_Host *host; struct isp1020_hostdata *hostdata; ENTER("isp1020_detect"); tmpt->proc_dir = &proc_scsi_isp1020; if (pcibios_present() == 0) { printk("qlogicisp : PCI bios not present\n"); return 0; } memset(irq2host, 0, sizeof(irq2host)); for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, index, &bus, &device_fn) == 0; index++) { host = scsi_register(tmpt, sizeof(struct isp1020_hostdata)); hostdata = (struct isp1020_hostdata *) host->hostdata; memset(hostdata, 0, sizeof(struct isp1020_hostdata)); hostdata->bus = bus; hostdata->device_fn = device_fn; if (isp1020_init(host) || isp1020_reset_hardware(host)#if USE_NVRAM_DEFAULTS || isp1020_get_defaults(host)#else || isp1020_set_defaults(host)#endif /* USE_NVRAM_DEFAULTS */ || isp1020_load_parameters(host)) { scsi_unregister(host); continue; } host->this_id = hostdata->host_param.initiator_scsi_id; if (request_irq(host->irq, isp1020_intr_handler, SA_INTERRUPT, "qlogicisp", NULL)) { printk("qlogicisp : interrupt %d already in use\n", host->irq); scsi_unregister(host); continue; } if (check_region(host->io_port, 0xff)) { printk("qlogicisp : i/o region 0x%04x-0x%04x already " "in use\n", host->io_port, host->io_port + 0xff); free_irq(host->irq, NULL); scsi_unregister(host); continue; } request_region(host->io_port, 0xff, "qlogicisp"); irq2host[host->irq] = host; outw(0x0, host->io_port + PCI_SEMAPHORE); outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); isp1020_enable_irqs(host); hosts++; } LEAVE("isp1020_detect"); return hosts;}int isp1020_release(struct Scsi_Host *host){ struct isp1020_hostdata *hostdata; ENTER("isp1020_release"); hostdata = (struct isp1020_hostdata *) host->hostdata; outw(0x0, host->io_port + PCI_INTF_CTL); free_irq(host->irq, NULL); release_region(host->io_port, 0xff); LEAVE("isp1020_release"); return 0;}const char *isp1020_info(struct Scsi_Host *host){ static char buf[80]; struct isp1020_hostdata *hostdata; ENTER("isp1020_info"); hostdata = (struct isp1020_hostdata *) host->hostdata; sprintf(buf, "QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%x", hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, host->irq, host->io_port); LEAVE("isp1020_info"); return buf;}/* * The middle SCSI layer ensures that queuecommand never gets invoked * concurrently with itself or the interrupt handler (though the * interrupt handler may call this routine as part of * request-completion handling). */int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *)){ int i, sg_count, n, num_free; u_int in_ptr, out_ptr; struct dataseg * ds; struct scatterlist *sg; struct Command_Entry *cmd; struct Continuation_Entry *cont; struct Scsi_Host *host; struct isp1020_hostdata *hostdata; ENTER("isp1020_queuecommand"); host = Cmnd->host; hostdata = (struct isp1020_hostdata *) host->hostdata; Cmnd->scsi_done = done; DEBUG(isp1020_print_scsi_cmd(Cmnd)); out_ptr = inw(host->io_port + MBOX4); in_ptr = hostdata->req_in_ptr; DEBUG(printk("qlogicisp : request queue depth %d\n", REQ_QUEUE_DEPTH(in_ptr, out_ptr))); cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; if (in_ptr == out_ptr) { printk("qlogicisp : request queue overflow\n"); return 1; } if (hostdata->send_marker) { struct Marker_Entry *marker; TRACE("queue marker", in_ptr, 0); DEBUG(printk("qlogicisp : adding marker entry\n")); marker = (struct Marker_Entry *) cmd; memset(marker, 0, sizeof(struct Marker_Entry)); marker->hdr.entry_type = ENTRY_MARKER; marker->hdr.entry_cnt = 1; marker->modifier = SYNC_ALL; hostdata->send_marker = 0; if (((in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN) == out_ptr) { outw(in_ptr, host->io_port + MBOX4); hostdata->req_in_ptr = in_ptr; printk("qlogicisp : request queue overflow\n"); return 1; } cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; } TRACE("queue command", in_ptr, Cmnd); memset(cmd, 0, sizeof(struct Command_Entry)); cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; cmd->handle = (u_int) virt_to_bus(Cmnd); cmd->target_lun = Cmnd->lun; cmd->target_id = Cmnd->target; cmd->cdb_length = Cmnd->cmd_len; cmd->control_flags = CFLAG_READ | CFLAG_WRITE; cmd->time_out = 30; memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->use_sg) { cmd->segment_cnt = sg_count = Cmnd->use_sg; sg = (struct scatterlist *) Cmnd->request_buffer; ds = cmd->dataseg; /* fill in first four sg entries: */ n = sg_count; if (n > 4) n = 4; for (i = 0; i < n; i++) { ds[i].d_base = (u_int) virt_to_bus(sg->address); ds[i].d_count = sg->length; ++sg; } sg_count -= 4; while (sg_count > 0) { ++cmd->hdr.entry_cnt; cont = (struct Continuation_Entry *) &hostdata->req[in_ptr][0]; in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; if (in_ptr == out_ptr) { printk("isp1020: unexpected request queue " "overflow\n"); return 1; } TRACE("queue continuation", in_ptr, 0); cont->hdr.entry_type = ENTRY_CONTINUATION; cont->hdr.entry_cnt = 0; cont->hdr.sys_def_1 = 0; cont->hdr.flags = 0; cont->reserved = 0; ds = cont->dataseg; n = sg_count; if (n > 7) n = 7; for (i = 0; i < n; ++i) { ds[i].d_base = (u_int)virt_to_bus(sg->address); ds[i].d_count = sg->length; ++sg; } sg_count -= n; } } else { cmd->dataseg[0].d_base = (u_int) virt_to_bus(Cmnd->request_buffer); cmd->dataseg[0].d_count = (u_int) Cmnd->request_bufflen; cmd->segment_cnt = 1; } outw(in_ptr, host->io_port + MBOX4); hostdata->req_in_ptr = in_ptr; num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); host->can_queue = host->host_busy + num_free; host->sg_tablesize = QLOGICISP_MAX_SG(num_free); LEAVE("isp1020_queuecommand"); return 0;}#define ASYNC_EVENT_INTERRUPT 0x01void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs){ Scsi_Cmnd *Cmnd; struct Status_Entry *sts; struct Scsi_Host *host; struct isp1020_hostdata *hostdata; u_int in_ptr, out_ptr; u_short status; ENTER_INTR("isp1020_intr_handler"); host = irq2host[irq]; if (!host) { printk("qlogicisp : unexpected interrupt on line %d\n", irq); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -