📄 qlogicfc.c
字号:
#include "qlogicfc_asm.c"/* Each element in mbox_param is an 8 bit bitmap where each bit indicates if that mbox should be copied as input. For example 0x2 would mean only copy mbox1. */const u_char mbox_param[] ={ 0x01, /* MBOX_NO_OP */ 0x1f, /* MBOX_LOAD_RAM */ 0x03, /* MBOX_EXEC_FIRMWARE */ 0x1f, /* MBOX_DUMP_RAM */ 0x07, /* MBOX_WRITE_RAM_WORD */ 0x03, /* MBOX_READ_RAM_WORD */ 0xff, /* MBOX_MAILBOX_REG_TEST */ 0x03, /* MBOX_VERIFY_CHECKSUM */ 0x01, /* MBOX_ABOUT_FIRMWARE */ 0xff, /* MBOX_LOAD_RISC_RAM */ 0xff, /* MBOX_DUMP_RISC_RAM */ 0x00, /* 0x000b */ 0x00, /* 0x000c */ 0x00, /* 0x000d */ 0x01, /* MBOX_CHECK_FIRMWARE */ 0x00, /* 0x000f */ 0x1f, /* MBOX_INIT_REQ_QUEUE */ 0x2f, /* MBOX_INIT_RES_QUEUE */ 0x0f, /* MBOX_EXECUTE_IOCB */ 0x03, /* MBOX_WAKE_UP */ 0x01, /* MBOX_STOP_FIRMWARE */ 0x0f, /* MBOX_ABORT_IOCB */ 0x03, /* MBOX_ABORT_DEVICE */ 0x07, /* MBOX_ABORT_TARGET */ 0x03, /* MBOX_BUS_RESET */ 0x03, /* MBOX_STOP_QUEUE */ 0x03, /* MBOX_START_QUEUE */ 0x03, /* MBOX_SINGLE_STEP_QUEUE */ 0x03, /* MBOX_ABORT_QUEUE */ 0x03, /* MBOX_GET_DEV_QUEUE_STATUS */ 0x00, /* 0x001e */ 0x01, /* MBOX_GET_FIRMWARE_STATUS */ 0x01, /* MBOX_GET_INIT_SCSI_ID */ 0x00, /* 0x0021 */ 0x01, /* MBOX_GET_RETRY_COUNT */ 0x00, /* 0x0023 */ 0x00, /* 0x0024 */ 0x00, /* 0x0025 */ 0x00, /* 0x0026 */ 0x00, /* 0x0027 */ 0x03, /* MBOX_GET_TARGET_PARAMS */ 0x03, /* MBOX_GET_DEV_QUEUE_PARAMS */ 0x00, /* 0x002a */ 0x00, /* 0x002b */ 0x00, /* 0x002c */ 0x00, /* 0x002d */ 0x00, /* 0x002e */ 0x00, /* 0x002f */ 0x00, /* 0x0030 */ 0x00, /* 0x0031 */ 0x07, /* MBOX_SET_RETRY_COUNT */ 0x00, /* 0x0033 */ 0x00, /* 0x0034 */ 0x00, /* 0x0035 */ 0x00, /* 0x0036 */ 0x00, /* 0x0037 */ 0x0f, /* MBOX_SET_TARGET_PARAMS */ 0x0f, /* MBOX_SET_DEV_QUEUE_PARAMS */ 0x00, /* 0x003a */ 0x00, /* 0x003b */ 0x00, /* 0x003c */ 0x00, /* 0x003d */ 0x00, /* 0x003e */ 0x00, /* 0x003f */ 0x00, /* 0x0040 */ 0x00, /* 0x0041 */ 0x00, /* 0x0042 */ 0x00, /* 0x0043 */ 0x00, /* 0x0044 */ 0x00, /* 0x0045 */ 0x00, /* 0x0046 */ 0x00, /* 0x0047 */ 0x00, /* 0x0048 */ 0x00, /* 0x0049 */ 0x00, /* 0x004a */ 0x00, /* 0x004b */ 0x00, /* 0x004c */ 0x00, /* 0x004d */ 0x00, /* 0x004e */ 0x00, /* 0x004f */ 0x00, /* 0x0050 */ 0x00, /* 0x0051 */ 0x00, /* 0x0052 */ 0x00, /* 0x0053 */ 0xcf, /* MBOX_EXECUTE_IOCB64 */ 0x00, /* 0x0055 */ 0x00, /* 0x0056 */ 0x00, /* 0x0057 */ 0x00, /* 0x0058 */ 0x00, /* 0x0059 */ 0x00, /* 0x005a */ 0x00, /* 0x005b */ 0x00, /* 0x005c */ 0x00, /* 0x005d */ 0x00, /* 0x005e */ 0x00, /* 0x005f */ 0xff, /* MBOX_INIT_FIRMWARE */ 0xcd, /* MBOX_GET_INIT_CB */ 0x01, /* MBOX_INIT_LIP */ 0xcd, /* MBOX_GET_POS_MAP */ 0xcf, /* MBOX_GET_PORT_DB */ 0x03, /* MBOX_CLEAR_ACA */ 0x03, /* MBOX_TARGET_RESET */ 0x03, /* MBOX_CLEAR_TASK_SET */ 0x03, /* MBOX_ABORT_TASK_SET */ 0x01, /* MBOX_GET_FIRMWARE_STATE */ 0x03, /* MBOX_GET_PORT_NAME */ 0x00, /* 0x006b */ 0x00, /* 0x006c */ 0x00, /* 0x006d */ 0xcf, /* MBOX_SEND_SNS */ 0x0f, /* MBOX_PORT_LOGIN */ 0x03, /* MBOX_SEND_CHANGE_REQUEST */ 0x03, /* MBOX_PORT_LOGOUT */};#define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short))struct id_name_map { u64 wwn; u_char loop_id;};struct sns_cb { u_short len; u_short res1; u_int response_low; u_int response_high; u_short sub_len; u_short res2; u_char data[44];};/* address of instance of this struct is passed to adapter to initialize things */struct init_cb { u_char version; u_char reseverd1[1]; u_short firm_opts; u_short max_frame_len; u_short max_iocb; u_short exec_throttle; u_char retry_cnt; u_char retry_delay; u_short node_name[4]; u_short hard_addr; u_char reserved2[10]; u_short req_queue_out; u_short res_queue_in; u_short req_queue_len; u_short res_queue_len; u_int req_queue_addr_lo; u_int req_queue_addr_high; u_int res_queue_addr_lo; u_int res_queue_addr_high; /* the rest of this structure only applies to the isp2200 */ u_short lun_enables; u_char cmd_resource_cnt; u_char notify_resource_cnt; u_short timeout; u_short reserved3; u_short add_firm_opts; u_char res_accum_timer; u_char irq_delay_timer; u_short special_options; u_short reserved4[13];};/* * The result queue can be quite a bit smaller since continuation entries * do not show up there: */#define RES_QUEUE_LEN ((QLOGICFC_REQ_QUEUE_LEN + 1) / 8 - 1)#define QUEUE_ENTRY_LEN 64#if ISP2x00_FABRIC#define QLOGICFC_MAX_ID 0xff#else#define QLOGICFC_MAX_ID 0x7d#endif#define QLOGICFC_MAX_LUN 128#define QLOGICFC_MAX_LOOP_ID 0x7d/* the following connection options only apply to the 2200. i have only * had success with LOOP_ONLY and P2P_ONLY. */#define LOOP_ONLY 0#define P2P_ONLY 1#define LOOP_PREFERED 2#define P2P_PREFERED 3#define CONNECTION_PREFERENCE LOOP_ONLY/* adapter_state values */#define AS_FIRMWARE_DEAD -1#define AS_LOOP_DOWN 0#define AS_LOOP_GOOD 1#define AS_REDO_FABRIC_PORTDB 2#define AS_REDO_LOOP_PORTDB 4#define RES_SIZE ((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN)#define REQ_SIZE ((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN)struct isp2x00_hostdata { u_char revision; struct pci_dev *pci_dev; /* result and request queues (shared with isp2x00): */ 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; char * req; struct init_cb control_block; int adapter_state; unsigned long int tag_ages[QLOGICFC_MAX_ID + 1]; Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1]; unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1]; struct id_name_map port_db[QLOGICFC_MAX_ID + 1]; u_char mbox_done; u64 wwn; u_int port_id; u_char queued; u_char host_id; struct timer_list explore_timer;};/* 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, \ QLOGICFC_REQ_QUEUE_LEN)#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN)static void isp2x00_enable_irqs(struct Scsi_Host *);static void isp2x00_disable_irqs(struct Scsi_Host *);static int isp2x00_init(struct Scsi_Host *);static int isp2x00_reset_hardware(struct Scsi_Host *);static int isp2x00_mbox_command(struct Scsi_Host *, u_short[]);static int isp2x00_return_status(Scsi_Cmnd *, struct Status_Entry *);static void isp2x00_intr_handler(int, void *, struct pt_regs *);static void do_isp2x00_intr_handler(int, void *, struct pt_regs *);static int isp2x00_make_portdb(struct Scsi_Host *);#if ISP2x00_FABRICstatic int isp2x00_init_fabric(struct Scsi_Host *, struct id_name_map *, int);#endif#if USE_NVRAM_DEFAULTSstatic int isp2x00_get_nvram_defaults(struct Scsi_Host *, struct init_cb *);static u_short isp2x00_read_nvram_word(struct Scsi_Host *, u_short);#endif#if DEBUG_ISP2x00static void isp2x00_print_scsi_cmd(Scsi_Cmnd *);#endif#if DEBUG_ISP2x00_INTRstatic void isp2x00_print_status_entry(struct Status_Entry *);#endifstatic inline void isp2x00_enable_irqs(struct Scsi_Host *host){ outw(ISP_EN_INT | ISP_EN_RISC, host->io_port + PCI_INTER_CTL);}static inline void isp2x00_disable_irqs(struct Scsi_Host *host){ outw(0x0, host->io_port + PCI_INTER_CTL);}int isp2x00_detect(Scsi_Host_Template * tmpt){ int hosts = 0; int wait_time; struct Scsi_Host *host = NULL; struct isp2x00_hostdata *hostdata; struct pci_dev *pdev = NULL; unsigned short device_ids[2]; dma64_addr_t busaddr; int i; ENTER("isp2x00_detect"); device_ids[0] = PCI_DEVICE_ID_QLOGIC_ISP2100; device_ids[1] = PCI_DEVICE_ID_QLOGIC_ISP2200; tmpt->proc_name = "isp2x00"; if (pci_present() == 0) { printk("qlogicfc : PCI not present\n"); return 0; } for (i=0; i<2; i++){ while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, device_ids[i], pdev))) { if (pci_enable_device(pdev)) continue; host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata)); host->max_id = QLOGICFC_MAX_ID + 1; host->max_lun = QLOGICFC_MAX_LUN; host->hostt->use_new_eh_code = 1; hostdata = (struct isp2x00_hostdata *) host->hostdata; memset(hostdata, 0, sizeof(struct isp2x00_hostdata)); hostdata->pci_dev = pdev; hostdata->res = pci64_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr); if (!hostdata->res){ printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hostdata->host_id); scsi_unregister(host); continue; } hostdata->req = hostdata->res + (RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN; hostdata->queued = 0; /* set up the control block */ hostdata->control_block.version = 0x1; hostdata->control_block.firm_opts = cpu_to_le16(0x800e); hostdata->control_block.max_frame_len = cpu_to_le16(2048); hostdata->control_block.max_iocb = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN); hostdata->control_block.exec_throttle = cpu_to_le16(QLOGICFC_CMD_PER_LUN); hostdata->control_block.retry_delay = 5; hostdata->control_block.retry_cnt = 1; hostdata->control_block.node_name[0] = cpu_to_le16(0x0020); hostdata->control_block.node_name[1] = cpu_to_le16(0xE000); hostdata->control_block.node_name[2] = cpu_to_le16(0x008B); hostdata->control_block.node_name[3] = cpu_to_le16(0x0000); hostdata->control_block.hard_addr = cpu_to_le16(0x0003); hostdata->control_block.req_queue_len = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN + 1); hostdata->control_block.res_queue_len = cpu_to_le16(RES_QUEUE_LEN + 1); hostdata->control_block.res_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr)); hostdata->control_block.res_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr)); hostdata->control_block.req_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr + RES_SIZE)); hostdata->control_block.req_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr + RES_SIZE)); hostdata->control_block.add_firm_opts |= cpu_to_le16(CONNECTION_PREFERENCE<<4); hostdata->adapter_state = AS_LOOP_DOWN; hostdata->explore_timer.data = 1; hostdata->host_id = hosts; if (isp2x00_init(host) || isp2x00_reset_hardware(host)) { pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } host->this_id = 0; if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { printk("qlogicfc%d : interrupt %d already in use\n", hostdata->host_id, host->irq); pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } if (check_region(host->io_port, 0xff)) { printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " "in use\n", hostdata->host_id, host->io_port, host->io_port + 0xff); free_irq(host->irq, host); pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } request_region(host->io_port, 0xff, "qlogicfc"); outw(0x0, host->io_port + PCI_SEMAPHORE); outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); isp2x00_enable_irqs(host); /* wait for the loop to come up */ for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->adapter_state == AS_LOOP_DOWN;) barrier(); if (hostdata->adapter_state == AS_LOOP_DOWN) { printk("qlogicfc%d : link is not up\n", hostdata->host_id); } hosts++; hostdata->explore_timer.data = 0; } } /* this busy loop should not be needed but the isp2x00 seems to need some time before recognizing it is attached to a fabric */#if ISP2x00_FABRIC for (wait_time = jiffies + 5 * HZ; wait_time > jiffies;) barrier();#endif LEAVE("isp2x00_detect"); return hosts;}static int isp2x00_make_portdb(struct Scsi_Host *host){ short param[8]; int i, j; struct id_name_map temp[QLOGICFC_MAX_ID + 1]; struct isp2x00_hostdata *hostdata; isp2x00_disable_irqs(host); memset(temp, 0, sizeof(temp)); hostdata = (struct isp2x00_hostdata *) host->hostdata;#if ISP2x00_FABRIC for (i = 0x81; i < QLOGICFC_MAX_ID; i++) { param[0] = MBOX_PORT_LOGOUT; param[1] = i << 8; param[2] = 0; param[3] = 0; isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { DEBUG_FABRIC(printk("qlogicfc%d : logout failed %x %x\n", hostdata->host_id, i, param[0])); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -