📄 qla1280.c
字号:
"qla1280: dma direction bits don't match\n"); return 0; }#ifdef MODULE /* * If we are called as a module, the qla1280 pointer may not be null * and it would point to our bootup string, just like on the lilo * command line. IF not NULL, then process this config string with * qla1280_setup * * Boot time Options * To add options at boot time add a line to your lilo.conf file like: * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}" * which will result in the first four devices on the first two * controllers being set to a tagged queue depth of 32. */ if (qla1280) qla1280_setup(qla1280);#endif /* First Initialize QLA12160 on PCI Bus 1 Dev 2 */ while ((pdev = pci_find_device(id->vendor, id->device, pdev))) { if (pdev->bus->number == 1 && PCI_SLOT(pdev->devfn) == 2) { if (!qla1280_probe_one(pdev, id)) num_hosts++; } } pdev = NULL; /* Try and find each different type of adapter we support */ for (id = &qla1280_pci_tbl[0]; id->device; id++) { while ((pdev = pci_find_device(id->vendor, id->device, pdev))) { /* * skip QLA12160 already initialized on * PCI Bus 1 Dev 2 since we already initialized * and presented it */ if (id->device == PCI_DEVICE_ID_QLOGIC_ISP12160 && pdev->bus->number == 1 && PCI_SLOT(pdev->devfn) == 2) continue; if (!qla1280_probe_one(pdev, id)) num_hosts++; } } return num_hosts;}/* * This looks a bit ugly as we could just pass down host to * qla1280_remove_one, but I want to keep qla1280_release purely a wrapper * around pci_driver::remove as used from 2.6 onwards. */static intqla1280_release(struct Scsi_Host *host){ struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; qla1280_remove_one(ha->pdev); return 0;}static intqla1280_biosparam_old(Disk * disk, kdev_t dev, int geom[]){ return qla1280_biosparam(disk->device, NULL, disk->capacity, geom);}static intqla1280_proc_info_old(char *buffer, char **start, off_t offset, int length, int hostno, int inout){ struct Scsi_Host *host; for (host = scsi_hostlist; host; host = host->next) { if (host->host_no == hostno) { return qla1280_proc_info(host, buffer, start, offset, length, inout); } } return -ESRCH;}#endif/************************************************************************** * qla1280_intr_handler * Handles the H/W interrupt **************************************************************************/static irqreturn_tqla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs){ struct scsi_qla_host *ha; struct device_reg *reg; u16 data; int handled = 0; ENTER_INTR ("qla1280_intr_handler"); ha = (struct scsi_qla_host *)dev_id; spin_lock(HOST_LOCK); ha->isr_count++; reg = ha->iobase; WRT_REG_WORD(®->ictrl, 0); /* disable our interrupt. */ data = qla1280_debounce_register(®->istatus); /* Check for pending interrupts. */ if (data & RISC_INT) { qla1280_isr(ha, &ha->done_q); handled = 1; } if (!list_empty(&ha->done_q)) qla1280_done(ha); spin_unlock(HOST_LOCK); /* enable our interrupt. */ WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); LEAVE_INTR("qla1280_intr_handler"); return IRQ_RETVAL(handled);}static intqla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target){ uint8_t mr; uint16_t mb[MAILBOX_REGISTER_COUNT]; struct nvram *nv; int status; nv = &ha->nvram; mr = BIT_3 | BIT_2 | BIT_1 | BIT_0; /* Set Target Parameters. */ mb[0] = MBC_SET_TARGET_PARAMETERS; mb[1] = (uint16_t) (bus ? target | BIT_7 : target); mb[1] <<= 8; mb[2] = (nv->bus[bus].target[target].parameter.c << 8); if (IS_ISP1x160(ha)) { mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8) | nv->bus[bus].target[target].sync_period; mb[6] = (nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8) | nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; mr |= BIT_6; } else { mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8) | nv->bus[bus].target[target].sync_period; } status = qla1280_mailbox_command(ha, mr, &mb[0]); if (status) printk(KERN_WARNING "scsi(%ld:%i:%i): " "qla1280_set_target_parameters() failed\n", ha->host_no, bus, target); return status;}/************************************************************************** * qla1280_slave_configure * * Description: * Determines the queue depth for a given device. There are two ways * a queue depth can be obtained for a tagged queueing device. One * way is the default queue depth which is determined by whether * If it is defined, then it is used * as the default queue depth. Otherwise, we use either 4 or 8 as the * default queue depth (dependent on the number of hardware SCBs). **************************************************************************/static intqla1280_slave_configure(struct scsi_device *device){ struct scsi_qla_host *ha; int default_depth = 3; int bus = device->channel; int target = device->id; int status = 0; struct nvram *nv; unsigned long flags; ha = (struct scsi_qla_host *)device->host->hostdata; nv = &ha->nvram; if (qla1280_check_for_dead_scsi_bus(ha, bus)) return 1; if (device->tagged_supported && (ha->bus_settings[bus].qtag_enables & (BIT_0 << target))) { scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, ha->bus_settings[bus].hiwat); } else { scsi_adjust_queue_depth(device, 0, default_depth); }#if LINUX_VERSION_CODE > 0x020500 nv->bus[bus].target[target].parameter.f.enable_sync = device->sdtr; nv->bus[bus].target[target].parameter.f.enable_wide = device->wdtr; nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = device->ppr;#endif if (driver_setup.no_sync || (driver_setup.sync_mask && (~driver_setup.sync_mask & (1 << target)))) nv->bus[bus].target[target].parameter.f.enable_sync = 0; if (driver_setup.no_wide || (driver_setup.wide_mask && (~driver_setup.wide_mask & (1 << target)))) nv->bus[bus].target[target].parameter.f.enable_wide = 0; if (IS_ISP1x160(ha)) { if (driver_setup.no_ppr || (driver_setup.ppr_mask && (~driver_setup.ppr_mask & (1 << target)))) nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0; } spin_lock_irqsave(HOST_LOCK, flags); if (nv->bus[bus].target[target].parameter.f.enable_sync) status = qla1280_set_target_parameters(ha, bus, target); qla1280_get_target_parameters(ha, device); spin_unlock_irqrestore(HOST_LOCK, flags); return status;}#if LINUX_VERSION_CODE < 0x020545/************************************************************************** * qla1280_select_queue_depth * * Sets the queue depth for each SCSI device hanging off the input * host adapter. We use a queue depth of 2 for devices that do not * support tagged queueing. **************************************************************************/static voidqla1280_select_queue_depth(struct Scsi_Host *host, struct scsi_device *sdev_q){ struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; struct scsi_device *sdev; ENTER("qla1280_select_queue_depth"); for (sdev = sdev_q; sdev; sdev = sdev->next) if (sdev->host == host) qla1280_slave_configure(sdev); if (sdev_q) qla1280_check_for_dead_scsi_bus(ha, sdev_q->channel); LEAVE("qla1280_select_queue_depth");}#endif/* * qla1280_done * Process completed commands. * * Input: * ha = adapter block pointer. * done_q = done queue. */static voidqla1280_done(struct scsi_qla_host *ha){ struct srb *sp; struct list_head *done_q; int bus, target, lun; struct scsi_cmnd *cmd; ENTER("qla1280_done"); done_q = &ha->done_q; while (!list_empty(done_q)) { sp = list_entry(done_q->next, struct srb, list); list_del(&sp->list); cmd = sp->cmd; bus = SCSI_BUS_32(cmd); target = SCSI_TCN_32(cmd); lun = SCSI_LUN_32(cmd); switch ((CMD_RESULT(cmd) >> 16)) { case DID_RESET: /* Issue marker command. */ qla1280_marker(ha, bus, target, 0, MK_SYNC_ID); break; case DID_ABORT: sp->flags &= ~SRB_ABORT_PENDING; sp->flags |= SRB_ABORTED; if (sp->flags & SRB_TIMEOUT) CMD_RESULT(sp->cmd) = DID_TIME_OUT << 16; break; default: break; } /* Release memory used for this I/O */ if (cmd->use_sg) { dprintk(3, "S/G unmap_sg cmd=%p\n", cmd); pci_unmap_sg(ha->pdev, cmd->request_buffer, cmd->use_sg, cmd->sc_data_direction); } else if (cmd->request_bufflen) { /*dprintk(1, "No S/G unmap_single cmd=%x saved_dma_handle=%lx\n", cmd, sp->saved_dma_handle); */ pci_unmap_page(ha->pdev, sp->saved_dma_handle, cmd->request_bufflen, cmd->sc_data_direction); } /* Call the mid-level driver interrupt handler */ CMD_HANDLE(sp->cmd) = (unsigned char *)INVALID_HANDLE; ha->actthreads--;#if LINUX_VERSION_CODE < 0x020500 if (cmd->cmnd[0] == INQUIRY) qla1280_get_target_options(cmd, ha);#endif (*(cmd)->scsi_done)(cmd); if(sp->wait != NULL) complete(sp->wait); } LEAVE("qla1280_done");}/* * Translates a ISP error to a Linux SCSI error */static intqla1280_return_status(struct response * sts, struct scsi_cmnd *cp){ int host_status = DID_ERROR; uint16_t comp_status = le16_to_cpu(sts->comp_status); uint16_t state_flags = le16_to_cpu(sts->state_flags); uint16_t residual_length = le16_to_cpu(sts->residual_length); uint16_t scsi_status = le16_to_cpu(sts->scsi_status);#if DEBUG_QLA1280_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_QLA1280_INTR */ ENTER("qla1280_return_status");#if DEBUG_QLA1280_INTR /* dprintk(1, "qla1280_return_status: compl status = 0x%04x\n", comp_status); */#endif switch (comp_status) { case CS_COMPLETE: host_status = DID_OK; break; case CS_INCOMPLETE: if (!(state_flags & SF_GOT_BUS)) host_status = DID_NO_CONNECT; else if (!(state_flags & SF_GOT_TARGET)) host_status = DID_BAD_TARGET; else if (!(state_flags & SF_SENT_CDB)) host_status = DID_ERROR; else if (!(state_flags & SF_TRANSFERRED_DATA)) host_status = DID_ERROR; else if (!(state_flags & SF_GOT_STATUS)) host_status = DID_ERROR; else if (!(state_flags & SF_GOT_SENSE)) host_status = DID_ERROR; break; case CS_RESET: 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: dprintk(2, "Data overrun 0x%x\n", residual_length); dprintk(2, "qla1280_isr: response packet data\n"); qla1280_dump_buffer(2, (char *)sts, RESPONSE_ENTRY_SIZE); host_status = DID_ERROR; break; case CS_DATA_UNDERRUN: if ((cp->request_bufflen - residual_length) < cp->underflow) { printk(KERN_WARNING "scsi: Underflow detected - retrying " "command.\n"); host_status = DID_ERROR; } else host_status = DID_OK; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -