📄 qla_os.c
字号:
loff_t off, size_t count){ struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, struct device, kobj))); uint16_t *witer; unsigned long flags; uint16_t cnt; if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t)) return 0; /* Read NVRAM. */ spin_lock_irqsave(&ha->hardware_lock, flags); qla2x00_lock_nvram_access(ha); witer = (uint16_t *)buf; for (cnt = 0; cnt < count / 2; cnt++) { *witer = cpu_to_le16(qla2x00_get_nvram_word(ha, cnt+ha->nvram_base)); witer++; } qla2x00_unlock_nvram_access(ha); spin_unlock_irqrestore(&ha->hardware_lock, flags); return (count);}static ssize_t qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off, size_t count){ struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, struct device, kobj))); uint8_t *iter; uint16_t *witer; unsigned long flags; uint16_t cnt; uint8_t chksum; if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t)) return 0; /* Checksum NVRAM. */ iter = (uint8_t *)buf; chksum = 0; for (cnt = 0; cnt < count - 1; cnt++) chksum += *iter++; chksum = ~chksum + 1; *iter = chksum; /* Write NVRAM. */ spin_lock_irqsave(&ha->hardware_lock, flags); qla2x00_lock_nvram_access(ha); qla2x00_release_nvram_protection(ha); witer = (uint16_t *)buf; for (cnt = 0; cnt < count / 2; cnt++) { qla2x00_write_nvram_word(ha, cnt+ha->nvram_base, cpu_to_le16(*witer)); witer++; } qla2x00_unlock_nvram_access(ha); spin_unlock_irqrestore(&ha->hardware_lock, flags); return (count);}/* -------------------------------------------------------------------------- */static char *qla2x00_get_pci_info_str(struct scsi_qla_host *ha, char *str){ static char *pci_bus_modes[] = { "33", "66", "100", "133", }; uint16_t pci_bus; strcpy(str, "PCI"); pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9; if (pci_bus) { strcat(str, "-X ("); strcat(str, pci_bus_modes[pci_bus]); } else { pci_bus = (ha->pci_attr & BIT_8) >> 8; strcat(str, " ("); strcat(str, pci_bus_modes[pci_bus]); } strcat(str, " MHz)"); return (str);}char *qla2x00_get_fw_version_str(struct scsi_qla_host *ha, char *str){ char un_str[10]; sprintf(str, "%d.%02d.%02d ", ha->fw_major_version, ha->fw_minor_version, ha->fw_subminor_version); if (ha->fw_attributes & BIT_9) { strcat(str, "FLX"); return (str); } switch (ha->fw_attributes & 0xFF) { case 0x7: strcat(str, "EF"); break; case 0x17: strcat(str, "TP"); break; case 0x37: strcat(str, "IP"); break; case 0x77: strcat(str, "VI"); break; default: sprintf(un_str, "(%x)", ha->fw_attributes); strcat(str, un_str); break; } if (ha->fw_attributes & 0x100) strcat(str, "X"); return (str);}/*************************************************************************** qla2x00_queuecommand** Description:* Queue a command to the controller.** Input:* cmd - pointer to Scsi cmd structure* fn - pointer to Scsi done function** Returns:* 0 - Always** Note:* The mid-level driver tries to ensures that queuecommand never gets invoked* concurrently with itself or the interrupt handler (although the* interrupt handler may call this routine as part of request-completion* handling).**************************************************************************/static intqla2x00_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)){ fc_port_t *fcport; os_lun_t *lq; os_tgt_t *tq; scsi_qla_host_t *ha, *ha2; srb_t *sp; struct Scsi_Host *host; unsigned int b, t, l; unsigned long handle; int was_empty; host = cmd->device->host; ha = (scsi_qla_host_t *) host->hostdata; was_empty = 1; cmd->scsi_done = fn; spin_unlock_irq(ha->host->host_lock); /* * Allocate a command packet from the "sp" pool. If we cant get back * one then let scsi layer come back later. */ if ((sp = qla2x00_get_new_sp(ha)) == NULL) { qla_printk(KERN_WARNING, ha, "Couldn't allocate memory for sp - retried.\n"); spin_lock_irq(ha->host->host_lock); return (1); } sp->cmd = cmd; CMD_SP(cmd) = (void *)sp; sp->flags = 0; if (CMD_RESID_LEN(cmd) & SRB_IOCTL) { /* Need to set sp->flags */ sp->flags |= SRB_IOCTL; CMD_RESID_LEN(cmd) = 0; /* Clear it since no more use. */ } sp->fo_retry_cnt = 0; sp->err_id = 0; /* Generate LU queue on bus, target, LUN */ b = cmd->device->channel; t = cmd->device->id; l = cmd->device->lun; /* * Start Command Timer. Typically it will be 2 seconds less than what * is requested by the Host such that we can return the IO before * aborts are called. */ if ((cmd->timeout_per_command / HZ) > QLA_CMD_TIMER_DELTA) qla2x00_add_timer_to_cmd(sp, (cmd->timeout_per_command / HZ) - QLA_CMD_TIMER_DELTA); else qla2x00_add_timer_to_cmd(sp, cmd->timeout_per_command / HZ); if (l >= ha->max_luns) { cmd->result = DID_NO_CONNECT << 16; sp->err_id = SRB_ERR_PORT; spin_lock_irq(ha->host->host_lock); sp_put(ha, sp); return (0); } if ((tq = (os_tgt_t *) TGT_Q(ha, t)) != NULL && (lq = (os_lun_t *) LUN_Q(ha, t, l)) != NULL) { fcport = lq->fclun->fcport; ha2 = fcport->ha; } else { lq = NULL; fcport = NULL; ha2 = ha; } /* Set an invalid handle until we issue the command to ISP */ /* then we will set the real handle value. */ handle = INVALID_HANDLE; cmd->host_scribble = (unsigned char *)handle; /* Bookkeeping information */ sp->r_start = jiffies; /* Time the request was recieved. */ sp->u_start = 0; /* Setup device queue pointers. */ sp->tgt_queue = tq; sp->lun_queue = lq; /* * NOTE : q is NULL * * 1. When device is added from persistent binding but has not been * discovered yet.The state of loopid == PORT_AVAIL. * 2. When device is never found on the bus.(loopid == UNUSED) * * IF Device Queue is not created, or device is not in a valid state * and link down error reporting is enabled, reject IO. */ if (fcport == NULL) { DEBUG3(printk("scsi(%ld:%2d:%2d): port unavailable\n", ha->host_no,t,l)); cmd->result = DID_NO_CONNECT << 16; sp->err_id = SRB_ERR_PORT; spin_lock_irq(ha->host->host_lock); sp_put(ha, sp); return (0); } /* Only modify the allowed count if the target is a *non* tape device */ if ((fcport->flags & FCF_TAPE_PRESENT) == 0) { sp->flags &= ~SRB_TAPE; if (cmd->allowed < ql2xretrycount) { cmd->allowed = ql2xretrycount; } } else sp->flags |= SRB_TAPE; DEBUG5(printk("scsi(%ld:%2d:%2d): (queuecmd) queue sp = %p, " "flags=0x%x fo retry=%d, pid=%ld\n", ha->host_no, t, l, sp, sp->flags, sp->fo_retry_cnt, cmd->serial_number)); DEBUG5(qla2x00_print_scsi_cmd(cmd)); sp->fclun = lq->fclun; sp->ha = ha2; if (cmd->sc_data_direction == DMA_BIDIRECTIONAL && cmd->request_bufflen != 0) { DEBUG2(printk(KERN_WARNING "scsi(%ld): Incorrect data direction - transfer " "length=%d, direction=%d, pid=%ld, opcode=%x\n", ha->host_no, cmd->request_bufflen, cmd->sc_data_direction, cmd->serial_number, cmd->cmnd[0])); } /* Final pre-check : * * Either PORT_DOWN_TIMER OR LINK_DOWN_TIMER Expired. */ if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || atomic_read(&ha2->loop_state) == LOOP_DEAD) { /* * Add the command to the done-queue for later failover * processing. */ cmd->result = DID_NO_CONNECT << 16; if (atomic_read(&ha2->loop_state) == LOOP_DOWN) sp->err_id = SRB_ERR_LOOP; else sp->err_id = SRB_ERR_PORT; add_to_done_queue(ha, sp); qla2x00_done(ha); spin_lock_irq(ha->host->host_lock); return (0); } if (tq && test_bit(TQF_SUSPENDED, &tq->flags) && (sp->flags & SRB_TAPE) == 0) { /* If target suspended put incoming I/O in retry_q. */ qla2x00_extend_timeout(sp->cmd, 10); add_to_scsi_retry_queue(ha, sp); } else was_empty = add_to_pending_queue(ha, sp); if ((IS_QLA2100(ha) || IS_QLA2200(ha)) && ha->flags.online) { if (ha->response_ring_ptr->signature != RESPONSE_PROCESSED) { unsigned long flags; spin_lock_irqsave(&ha->hardware_lock, flags); qla2x00_process_response_queue(ha); spin_unlock_irqrestore(&ha->hardware_lock, flags); } } /* We submit to the hardware if: * * 1) we're on the cpu the irq's arrive on or * 2) there are very few io's outstanding. * * In all other cases we'll let an irq pick up our IO and submit it * to the controller to improve affinity. */ if (_smp_processor_id() == ha->last_irq_cpu || was_empty) qla2x00_next(ha); spin_lock_irq(ha->host->host_lock); return (0);}/* * qla2x00_eh_wait_on_command * Waits for the command to be returned by the Firmware for some * max time. * * Input: * ha = actual ha whose done queue will contain the command * returned by firmware. * cmd = Scsi Command to wait on. * flag = Abort/Reset(Bus or Device Reset) * * Return: * Not Found : 0 * Found : 1 */static intqla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd){#define ABORT_POLLING_PERIOD HZ#define ABORT_WAIT_TIME ((10 * HZ) / (ABORT_POLLING_PERIOD)) int found = 0; int done = 0; srb_t *rp = NULL; struct list_head *list, *temp; u_long max_wait_time = ABORT_WAIT_TIME; do { /* Check on done queue */ spin_lock(&ha->list_lock); list_for_each_safe(list, temp, &ha->done_queue) { rp = list_entry(list, srb_t, list); /* * Found command. Just exit and wait for the cmd sent * to OS. */ if (cmd == rp->cmd) { found++; DEBUG3(printk("%s: found in done queue.\n", __func__);) break; } } spin_unlock(&ha->list_lock); /* Complete the cmd right away. */ if (found) { qla2x00_delete_from_done_queue(ha, rp); sp_put(ha, rp); done++; break; } spin_unlock_irq(ha->host->host_lock); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(ABORT_POLLING_PERIOD); spin_lock_irq(ha->host->host_lock); } while ((max_wait_time--)); if (done) DEBUG2(printk(KERN_INFO "%s: found cmd=%p.\n", __func__, cmd)); return (done);}/* * qla2x00_wait_for_hba_online * Wait till the HBA is online after going through * <= MAX_RETRIES_OF_ISP_ABORT or * finally HBA is disabled ie marked offline * * Input: * ha - pointer to host adapter structure * * Note: * Does context switching-Release SPIN_LOCK * (if any) before calling this routine. * * Return: * Success (Adapter is online) : 0 * Failed (Adapter is offline/disabled) : 1 */static int qla2x00_wait_for_hba_online(scsi_qla_host_t *ha){ int return_status; unsigned long wait_online; wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ); while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) || test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) || ha->dpc_active) && time_before(jiffies, wait_online)) { msleep(1000); } if (ha->flags.online) return_status = QLA_SUCCESS; else return_status = QLA_FUNCTION_FAILED; DEBUG2(printk("%s return_status=%d\n",__func__,return_status)); return (return_status);}/* * qla2x00_wait_for_loop_ready * Wait for MAX_LOOP_TIMEOUT(5 min) value for loop * to be in LOOP_READY state. * Input: * ha - pointer to host adapter structure * * Note: * Does context switching-Release SPIN_LOCK * (if any) before calling this routine. * * * Return: * Success (LOOP_READY) : 0 * Failed (LOOP_NOT_READY) : 1 */static inline int qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha){ int return_status = QLA_SUCCESS; unsigned long loop_timeout ; /* wait for 5 min at the max for loop to be ready */ loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); while ((!atomic_read(&ha->loop_down_timer) && atomic_read(&ha->loop_state) == LOOP_DOWN) || test_bit(CFG_ACTIVE, &ha->cfg_flags) || atomic_read(&ha->loop_state) != LOOP_READY) { msleep(1000); if (time_after_eq(jiffies, loop_timeout)) { return_status = QLA_FUNCTION_FAILED; break; } } return (return_status); }/*************************************************************************** qla2xxx_eh_abort** Description:* The abort function will abort the specified command.** Input:* cmd = Linux SCSI command packet to be aborted.** Returns:* Either SUCCESS or FAILED.** Note:**************************************************************************/intqla2xxx_eh_abort(struct scsi_cmnd *cmd){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -