📄 qla1280.c
字号:
#if (BITS_PER_LONG == 64) || defined CONFIG_HIGHMEM#define QLA_64BIT_PTR 1#endif#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)#include <asm/sn/pci/pciio.h>/* Ugly hack needed for the virtual channel fix on SN2 */extern int snia_pcibr_rrb_alloc(struct pci_dev *pci_dev, int *count_vchan0, int *count_vchan1);#endif#ifdef QLA_64BIT_PTR#define pci_dma_hi32(a) ((a >> 16) >> 16)#else#define pci_dma_hi32(a) 0#endif#define pci_dma_lo32(a) (a & 0xffffffff)#define NVRAM_DELAY() udelay(500) /* 2 microseconds */#if LINUX_VERSION_CODE < 0x020500#define HOST_LOCK &io_request_lock#define irqreturn_t void#define IRQ_RETVAL(foo)#define MSG_ORDERED_TAG 1#define DMA_BIDIRECTIONAL SCSI_DATA_UNKNOWN#define DMA_TO_DEVICE SCSI_DATA_WRITE#define DMA_FROM_DEVICE SCSI_DATA_READ#define DMA_NONE SCSI_DATA_NONE#ifndef HAVE_SECTOR_Ttypedef unsigned int sector_t;#endifstatic inline voidscsi_adjust_queue_depth(struct scsi_device *device, int tag, int depth){ if (tag) { device->tagged_queue = tag; device->current_tag = 0; } device->queue_depth = depth;}static inline struct Scsi_Host *scsi_host_alloc(Scsi_Host_Template *t, size_t s){ return scsi_register(t, s);}static inline void scsi_host_put(struct Scsi_Host *h){ scsi_unregister(h);}#else#define HOST_LOCK ha->host->host_lock#endif#if LINUX_VERSION_CODE < 0x020600#define DEV_SIMPLE_TAGS(device) device->tagged_queue/* * Hack around that qla1280_remove_one is called from * qla1280_release in 2.4 */#undef __devexit#define __devexit#else#define DEV_SIMPLE_TAGS(device) device->simple_tags#endif#if defined(__ia64__) && !defined(ia64_platform_is)#define ia64_platform_is(foo) (!strcmp(x, platform_name))#endif#define IS_ISP1040(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020)#define IS_ISP1x40(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020 || \ ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240)#define IS_ISP1x160(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160 || \ ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160)static int qla1280_probe_one(struct pci_dev *, const struct pci_device_id *);static void qla1280_remove_one(struct pci_dev *);/* * QLogic Driver Support Function Prototypes. */static void qla1280_done(struct scsi_qla_host *);#if LINUX_VERSION_CODE < 0x020545static void qla1280_get_target_options(struct scsi_cmnd *, struct scsi_qla_host *);#endifstatic int qla1280_get_token(char *);static int qla1280_setup(char *s) __init;/* * QLogic ISP1280 Hardware Support Function Prototypes. */static int qla1280_load_firmware(struct scsi_qla_host *);static int qla1280_init_rings(struct scsi_qla_host *);static int qla1280_nvram_config(struct scsi_qla_host *);static int qla1280_mailbox_command(struct scsi_qla_host *, uint8_t, uint16_t *);static int qla1280_bus_reset(struct scsi_qla_host *, int);static int qla1280_device_reset(struct scsi_qla_host *, int, int);static int qla1280_abort_device(struct scsi_qla_host *, int, int, int);static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int);static int qla1280_abort_isp(struct scsi_qla_host *);#ifdef QLA_64BIT_PTRstatic int qla1280_64bit_start_scsi(struct scsi_qla_host *, struct srb *);#elsestatic int qla1280_32bit_start_scsi(struct scsi_qla_host *, struct srb *);#endifstatic void qla1280_nv_write(struct scsi_qla_host *, uint16_t);static void qla1280_poll(struct scsi_qla_host *);static void qla1280_reset_adapter(struct scsi_qla_host *);static void qla1280_marker(struct scsi_qla_host *, int, int, int, u8);static void qla1280_isp_cmd(struct scsi_qla_host *);static void qla1280_isr(struct scsi_qla_host *, struct list_head *);static void qla1280_rst_aen(struct scsi_qla_host *);static void qla1280_status_entry(struct scsi_qla_host *, struct response *, struct list_head *);static void qla1280_error_entry(struct scsi_qla_host *, struct response *, struct list_head *);static uint16_t qla1280_get_nvram_word(struct scsi_qla_host *, uint32_t);static uint16_t qla1280_nvram_request(struct scsi_qla_host *, uint32_t);static uint16_t qla1280_debounce_register(volatile uint16_t *);static request_t *qla1280_req_pkt(struct scsi_qla_host *);static int qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *, unsigned int);static void qla1280_get_target_parameters(struct scsi_qla_host *, struct scsi_device *);static int qla1280_set_target_parameters(struct scsi_qla_host *, int, int);static struct qla_driver_setup driver_setup __initdata;/* * convert scsi data direction to request_t control flags */static inline uint16_tqla1280_data_direction(struct scsi_cmnd *cmnd){ switch(cmnd->sc_data_direction) { case DMA_FROM_DEVICE: return BIT_5; case DMA_TO_DEVICE: return BIT_6; case DMA_BIDIRECTIONAL: return BIT_5 | BIT_6; /* * We could BUG() on default here if one of the four cases aren't * met, but then again if we receive something like that from the * SCSI layer we have more serious problems. This shuts up GCC. */ case DMA_NONE: default: return 0; }} #if DEBUG_QLA1280static void __qla1280_print_scsi_cmd(struct scsi_cmnd * cmd);static void __qla1280_dump_buffer(char *, int);#endif/* * insmod needs to find the variable and make it point to something */#ifdef MODULEstatic char *qla1280;/* insmod qla1280 options=verbose" */MODULE_PARM(qla1280, "s");#else__setup("qla1280=", qla1280_setup);#endif/* * We use the scsi_pointer structure that's included with each scsi_command * to overlay our struct srb over it. qla1280_init() checks that a srb is not * bigger than a scsi_pointer. */#define CMD_SP(Cmnd) &Cmnd->SCp#define CMD_CDBLEN(Cmnd) Cmnd->cmd_len#define CMD_CDBP(Cmnd) Cmnd->cmnd#define CMD_SNSP(Cmnd) Cmnd->sense_buffer#define CMD_SNSLEN(Cmnd) sizeof(Cmnd->sense_buffer)#define CMD_RESULT(Cmnd) Cmnd->result#define CMD_HANDLE(Cmnd) Cmnd->host_scribble#if LINUX_VERSION_CODE < 0x020545#define CMD_REQUEST(Cmnd) Cmnd->request.cmd#else#define CMD_REQUEST(Cmnd) Cmnd->request->cmd#endif#define CMD_HOST(Cmnd) Cmnd->device->host#define SCSI_BUS_32(Cmnd) Cmnd->device->channel#define SCSI_TCN_32(Cmnd) Cmnd->device->id#define SCSI_LUN_32(Cmnd) Cmnd->device->lun/*****************************************//* ISP Boards supported by this driver *//*****************************************/struct qla_boards { unsigned char name[9]; /* Board ID String */ int numPorts; /* Number of SCSI ports */ unsigned short *fwcode; /* pointer to FW array */ unsigned short *fwlen; /* number of words in array */ unsigned short *fwstart; /* start address for F/W */ unsigned char *fwver; /* Ptr to F/W version array */};/* NOTE: qla1280_pci_tbl and ql1280_board_tbl must be in the same order */static struct pci_device_id qla1280_pci_tbl[] = { {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP12160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1080, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1280, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP10160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, {0,}};MODULE_DEVICE_TABLE(pci, qla1280_pci_tbl);static struct qla_boards ql1280_board_tbl[] = { /* Name , Number of ports, FW details */ {"QLA12160", 2, &fw12160i_code01[0], &fw12160i_length01, &fw12160i_addr01, &fw12160i_version_str[0]}, {"QLA1080", 1, &fw1280ei_code01[0], &fw1280ei_length01, &fw1280ei_addr01, &fw1280ei_version_str[0]}, {"QLA1240", 2, &fw1280ei_code01[0], &fw1280ei_length01, &fw1280ei_addr01, &fw1280ei_version_str[0]}, {"QLA1280", 2, &fw1280ei_code01[0], &fw1280ei_length01, &fw1280ei_addr01, &fw1280ei_version_str[0]}, {"QLA10160", 1, &fw12160i_code01[0], &fw12160i_length01, &fw12160i_addr01, &fw12160i_version_str[0]}, {" ", 0}};static int qla1280_verbose = 1;static int qla1280_buffer_size;static char *qla1280_buffer;#if DEBUG_QLA1280static int ql_debug_level = 1;#define dprintk(level, format, a...) \ do { if (ql_debug_level >= level) printk(KERN_ERR format, ##a); } while(0)#define qla1280_dump_buffer(level, buf, size) \ if (ql_debug_level >= level) __qla1280_dump_buffer(buf, size)#define qla1280_print_scsi_cmd(level, cmd) \ if (ql_debug_level >= level) __qla1280_print_scsi_cmd(cmd)#else#define ql_debug_level 0#define dprintk(level, format, a...) do{}while(0)#define qla1280_dump_buffer(a, b, c) do{}while(0)#define qla1280_print_scsi_cmd(a, b) do{}while(0)#endif#define ENTER(x) dprintk(3, "qla1280 : Entering %s()\n", x);#define LEAVE(x) dprintk(3, "qla1280 : Leaving %s()\n", x);#define ENTER_INTR(x) dprintk(4, "qla1280 : Entering %s()\n", x);#define LEAVE_INTR(x) dprintk(4, "qla1280 : Leaving %s()\n", x);/************************************************************************* * qla1280_proc_info * * Description: * Return information to handle /proc support for the driver. * * buffer - ptrs to a page buffer * * Returns: *************************************************************************/#define PROC_BUF &qla1280_buffer[len]static int qla1280_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout){ struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; struct qla_boards *bdp = &ql1280_board_tbl[ha->devnum]; int size = 0; int len = 0; if (inout) return -ENOSYS; /* * if our old buffer is the right size use it otherwise * allocate a new one. */ if (qla1280_buffer_size != PAGE_SIZE) { /* deallocate this buffer and get a new one */ if (qla1280_buffer != NULL) { free_page((unsigned long)qla1280_buffer); qla1280_buffer_size = 0; } qla1280_buffer = (char *)get_zeroed_page(GFP_KERNEL); } if (qla1280_buffer == NULL) { size = sprintf(buffer, "qla1280 - kmalloc error at line %d\n", __LINE__); return size; } /* save the size of our buffer */ qla1280_buffer_size = PAGE_SIZE; /* 3.20 clear the buffer we use for proc display */ memset(qla1280_buffer, 0, PAGE_SIZE); /* start building the print buffer */ size = sprintf(PROC_BUF, "QLogic PCI to SCSI Adapter for ISP 1280/12160:\n" " Firmware version: %2d.%02d.%02d, Driver version %s\n", bdp->fwver[0], bdp->fwver[1], bdp->fwver[2], QLA1280_VERSION); len += size; size = sprintf(PROC_BUF, "SCSI Host Adapter Information: %s\n", bdp->name); len += size; size = sprintf(PROC_BUF, "Request Queue count= 0x%x, Response " "Queue count= 0x%x\n", REQUEST_ENTRY_CNT, RESPONSE_ENTRY_CNT); len += size; size = sprintf(PROC_BUF, "Number of pending commands = 0x%lx\n", ha->actthreads); len += size; size = sprintf(PROC_BUF, "Number of free request entries = %d\n", ha->req_q_cnt); len += size; size = sprintf(PROC_BUF, "\n"); /* 1 */ len += size; if (len >= qla1280_buffer_size) { printk(KERN_WARNING "qla1280: Overflow buffer in qla1280_proc.c\n"); } if (offset > len - 1) { free_page((unsigned long) qla1280_buffer); qla1280_buffer = NULL; qla1280_buffer_size = length = 0; *start = NULL; } else { *start = &qla1280_buffer[offset]; /* Start of wanted data */ if (len - offset < length) { length = len - offset; } } return length;}static int qla1280_read_nvram(struct scsi_qla_host *ha){ uint16_t *wptr; uint8_t chksum; int cnt, i; struct nvram *nv; ENTER("qla1280_read_nvram"); if (driver_setup.no_nvram) return 1; printk(KERN_INFO "scsi(%ld): Reading NVRAM\n", ha->host_no); wptr = (uint16_t *)&ha->nvram; nv = &ha->nvram; chksum = 0; for (cnt = 0; cnt < 3; cnt++) { *wptr = qla1280_get_nvram_word(ha, cnt); chksum += *wptr & 0xff; chksum += (*wptr >> 8) & 0xff; wptr++; } if (nv->id0 != 'I' || nv->id1 != 'S' || nv->id2 != 'P' || nv->id3 != ' ' || nv->version < 1) { dprintk(2, "Invalid nvram ID or version!\n"); chksum = 1; } else { for (; cnt < sizeof(struct nvram); cnt++) { *wptr = qla1280_get_nvram_word(ha, cnt); chksum += *wptr & 0xff; chksum += (*wptr >> 8) & 0xff; wptr++; } } dprintk(3, "qla1280_read_nvram: NVRAM Magic ID= %c %c %c %02x" " version %i\n", nv->id0, nv->id1, nv->id2, nv->id3, nv->version); if (chksum) { if (!driver_setup.no_nvram) printk(KERN_WARNING "scsi(%ld): Unable to identify or " "validate NVRAM checksum, using default " "settings\n", ha->host_no); ha->nvram_valid = 0; } else ha->nvram_valid = 1; /* The firmware interface is, um, interesting, in that the * actual firmware image on the chip is little endian, thus, * the process of taking that image to the CPU would end up * little endian. However, the firmare interface requires it * to be read a word (two bytes) at a time. * * The net result of this would be that the word (and * doubleword) quantites in the firmware would be correct, but
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -