📄 qlogicfc.c
字号:
cmd->dataseg[0].d_count = cpu_to_le32(Cmnd->request_bufflen); cmd->segment_cnt = cpu_to_le16(1); } else { cmd->dataseg[0].d_base = 0;#if PCI64_DMA_BITS > 32 cmd->dataseg[0].d_base_hi = 0;#endif cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */ } switch (Cmnd->cmnd[0]) { case TEST_UNIT_READY: case START_STOP: break; case WRITE_10: case WRITE_6: case WRITE_BUFFER: case MODE_SELECT: cmd->control_flags = cpu_to_le16(CFLAG_WRITE); break; default: cmd->control_flags = cpu_to_le16(CFLAG_READ); break; } if (Cmnd->device->tagged_supported) { if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) { cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); hostdata->tag_ages[Cmnd->target] = jiffies; } else switch (Cmnd->tag) { case HEAD_OF_QUEUE_TAG: cmd->control_flags |= cpu_to_le16(CFLAG_HEAD_TAG); break; case ORDERED_QUEUE_TAG: cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); break; default: cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG); break; } } /* * TEST_UNIT_READY commands from scsi_scan will fail due to "overlapped * commands attempted" unless we setup at least a simple queue (midlayer * will embelish this once it can do an INQUIRY command to the device) */ else cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG); outw(in_ptr, host->io_port + MBOX4); hostdata->req_in_ptr = in_ptr; hostdata->queued++; num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); num_free = (num_free > 2) ? num_free - 2 : 0; host->can_queue = hostdata->queued + num_free; if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) host->can_queue = QLOGICFC_REQ_QUEUE_LEN; host->sg_tablesize = QLOGICFC_MAX_SG(num_free); /* this is really gross */ if (host->can_queue <= host->host_busy){ if (host->can_queue+2 < host->host_busy) DEBUG(printk("qlogicfc%d.c crosses its fingers.\n", hostdata->host_id)); host->can_queue = host->host_busy + 1; } LEAVE("isp2x00_queuecommand"); return 0;}/* we have received an event, such as a lip or an RSCN, which may mean that * our port database is incorrect so the port database must be recreated. */static void redo_port_db(unsigned long arg){ struct Scsi_Host * host = (struct Scsi_Host *) arg; struct isp2x00_hostdata * hostdata; unsigned long flags; int i; hostdata = (struct isp2x00_hostdata *) host->hostdata; hostdata->explore_timer.data = 0; del_timer(&hostdata->explore_timer); spin_lock_irqsave(&io_request_lock, flags); if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) { isp2x00_make_portdb(host); printk("qlogicfc%d : Port Database\n", hostdata->host_id); for (i = 0; hostdata->port_db[i].wwn != 0; i++) { printk("wwn: %08x%08x scsi_id: %x loop_id: ", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i); if (hostdata->port_db[i].loop_id != hostdata->port_db[0].loop_id || i == 0) printk("%x", hostdata->port_db[i].loop_id); else printk("Not Available"); printk("\n"); } for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++){ if (hostdata->handle_ptrs[i] && (hostdata->port_db[hostdata->handle_ptrs[i]->target].loop_id > QLOGICFC_MAX_LOOP_ID || hostdata->adapter_state & AS_REDO_LOOP_PORTDB)){ if (hostdata->port_db[hostdata->handle_ptrs[i]->target].loop_id != hostdata->port_db[0].loop_id){ hostdata->handle_ptrs[i]->result = DID_SOFT_ERROR << 16; if (hostdata->handle_ptrs[i]->scsi_done){ (*hostdata->handle_ptrs[i]->scsi_done) (hostdata->handle_ptrs[i]); } else printk("qlogicfc%d : done is null?\n", hostdata->host_id); hostdata->handle_ptrs[i] = NULL; hostdata->handle_serials[i] = 0; } } } hostdata->adapter_state = AS_LOOP_GOOD; } spin_unlock_irqrestore(&io_request_lock, flags);}#define ASYNC_EVENT_INTERRUPT 0x01void do_isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs){ unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); isp2x00_intr_handler(irq, dev_id, regs); spin_unlock_irqrestore(&io_request_lock, flags);}void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs){ Scsi_Cmnd *Cmnd; struct Status_Entry *sts; struct Scsi_Host *host = dev_id; struct isp2x00_hostdata *hostdata; u_int in_ptr, out_ptr, handle, num_free; u_short status; ENTER_INTR("isp2x00_intr_handler"); hostdata = (struct isp2x00_hostdata *) host->hostdata; DEBUG_INTR(printk("qlogicfc%d : interrupt on line %d\n", hostdata->host_id, irq)); if (!(inw(host->io_port + PCI_INTER_STS) & 0x08)) { /* spurious interrupts can happen legally */ DEBUG_INTR(printk("qlogicfc%d : got spurious interrupt\n", hostdata->host_id)); return; } in_ptr = inw(host->io_port + MBOX5); out_ptr = hostdata->res_out_ptr; if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) { status = inw(host->io_port + MBOX0); DEBUG_INTR(printk("qlogicfc%d : mbox completion status: %x\n", hostdata->host_id, status)); switch (status) { case LOOP_UP: case POINT_TO_POINT_UP: printk("qlogicfc%d : Link is Up\n", hostdata->host_id); hostdata->adapter_state = AS_REDO_FABRIC_PORTDB | AS_REDO_LOOP_PORTDB; break; case LOOP_DOWN: printk("qlogicfc%d : Link is Down\n", hostdata->host_id); hostdata->adapter_state = AS_LOOP_DOWN; break; case CONNECTION_MODE: printk("received CONNECTION_MODE irq %x\n", inw(host->io_port + MBOX1)); break; case CHANGE_NOTIFICATION: printk("qlogicfc%d : RSCN Received\n", hostdata->host_id); if (hostdata->adapter_state == AS_LOOP_GOOD) hostdata->adapter_state = AS_REDO_FABRIC_PORTDB; break; case LIP_OCCURED: case LIP_RECEIVED: printk("qlogicfc%d : Loop Reinitialized\n", hostdata->host_id); if (hostdata->adapter_state == AS_LOOP_GOOD) hostdata->adapter_state = AS_REDO_LOOP_PORTDB; break; case SYSTEM_ERROR: printk("qlogicfc%d : The firmware just choked.\n", hostdata->host_id); hostdata->adapter_state = AS_FIRMWARE_DEAD; break; case SCSI_COMMAND_COMPLETE: handle = inw(host->io_port + MBOX1) | (inw(host->io_port + MBOX2) << 16); Cmnd = hostdata->handle_ptrs[handle]; hostdata->handle_ptrs[handle] = NULL; hostdata->handle_serials[handle] = 0; hostdata->queued--; if (Cmnd != NULL) { Cmnd->result = 0x0; (*Cmnd->scsi_done) (Cmnd); } else printk("qlogicfc%d.c : got a null value out of handle_ptrs, this sucks\n", hostdata->host_id); break; case MBOX_COMMAND_COMPLETE: case INVALID_COMMAND: case HOST_INTERFACE_ERROR: case TEST_FAILED: case COMMAND_ERROR: case COMMAND_PARAM_ERROR: case PORT_ID_USED: case LOOP_ID_USED: case ALL_IDS_USED: hostdata->mbox_done = 1; outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); return; default: printk("qlogicfc%d : got an unknown status? %x\n", hostdata->host_id, status); } if ((hostdata->adapter_state & AS_REDO_LOOP_PORTDB || hostdata->adapter_state & AS_REDO_FABRIC_PORTDB) && hostdata->explore_timer.data == 0){ hostdata->explore_timer.function = redo_port_db; hostdata->explore_timer.data = (unsigned long)host; hostdata->explore_timer.expires = jiffies + (HZ/4); init_timer(&hostdata->explore_timer); add_timer(&hostdata->explore_timer); } outw(0x0, host->io_port + PCI_SEMAPHORE); } else { DEBUG_INTR(printk("qlogicfc%d : response queue update\n", hostdata->host_id)); DEBUG_INTR(printk("qlogicfc%d : response queue depth %d\n", hostdata->host_id, RES_QUEUE_DEPTH(in_ptr, out_ptr))); while (out_ptr != in_ptr) { unsigned le_hand; sts = (struct Status_Entry *) &hostdata->res[out_ptr*QUEUE_ENTRY_LEN]; out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; TRACE("done", out_ptr, Cmnd); DEBUG_INTR(isp2x00_print_status_entry(sts)); le_hand = le32_to_cpu(sts->handle); if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[le_hand])) { Cmnd->result = isp2x00_return_status(Cmnd, sts); hostdata->queued--; if (Cmnd->use_sg) pci64_unmap_sg(hostdata->pci_dev, (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) pci64_unmap_single(hostdata->pci_dev, *(dma64_addr_t *)&Cmnd->SCp, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); /* * if any of the following are true we do not * call scsi_done. if the status is CS_ABORTED * we dont have to call done because the upper * level should already know its aborted. */ if (hostdata->handle_serials[le_hand] != Cmnd->serial_number || le16_to_cpu(sts->completion_status) == CS_ABORTED){ hostdata->handle_serials[le_hand] = 0; hostdata->handle_ptrs[le_hand] = NULL; outw(out_ptr, host->io_port + MBOX5); continue; } /* * if we get back an error indicating the port * is not there or if the link is down and * this is a device that used to be there * allow the command to timeout. * the device may well be back in a couple of * seconds. */ if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == cpu_to_le16(CS_PORT_UNAVAILABLE) || sts->completion_status == cpu_to_le16(CS_PORT_LOGGED_OUT) || sts->completion_status == cpu_to_le16(CS_PORT_CONFIG_CHANGED)) && hostdata->port_db[Cmnd->target].wwn){ outw(out_ptr, host->io_port + MBOX5); continue; } } else { outw(out_ptr, host->io_port + MBOX5); continue; } hostdata->handle_ptrs[le_hand] = NULL; if (sts->completion_status == cpu_to_le16(CS_RESET_OCCURRED) || (sts->status_flags & cpu_to_le16(STF_BUS_RESET))) hostdata->send_marker = 1; if (le16_to_cpu(sts->scsi_status) & 0x0200) memcpy(Cmnd->sense_buffer, sts->req_sense_data, sizeof(Cmnd->sense_buffer)); outw(out_ptr, host->io_port + MBOX5); if (Cmnd->scsi_done != NULL) { (*Cmnd->scsi_done) (Cmnd); } else printk("qlogicfc%d : Ouch, scsi done is NULL\n", hostdata->host_id); } hostdata->res_out_ptr = out_ptr; } out_ptr = inw(host->io_port + MBOX4); in_ptr = hostdata->req_in_ptr; num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); num_free = (num_free > 2) ? num_free - 2 : 0; host->can_queue = hostdata->queued + num_free; if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) host->can_queue = QLOGICFC_REQ_QUEUE_LEN; host->sg_tablesize = QLOGICFC_MAX_SG(num_free); if (host->can_queue <= host->host_busy){ if (host->can_queue+2 < host->host_busy) DEBUG(printk("qlogicfc%d : crosses its fingers.\n", hostdata->host_id)); host->can_queue = host->host_busy + 1; } outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); LEAVE_INTR("isp2x00_intr_handler");}static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts){ int host_status = DID_ERROR;#if DEBUG_ISP2x00_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_ISP2x00_INTR */ ENTER("isp2x00_return_status"); DEBUG(printk("qlogicfc : completion status = 0x%04x\n", le16_to_cpu(sts->completion_status))); switch (le16_to_cpu(sts->completion_status)) { case CS_COMPLETE: host_status = DID_OK; break; case CS_DMA_ERROR: host_status = DID_ERROR; break; case CS_RESET_OCCURRED: 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: host_status = DID_ERROR; break; case CS_DATA_UNDERRUN: if (Cmnd->underflow <= (Cmnd->request_bufflen - le32_to_cpu(sts->residual))) host_status = DID_OK; else host_status = DID_ERROR; break; case CS_PORT_UNAVAILABLE: case CS_PORT_LOGGED_OUT: case CS_PORT_CONFIG_CHANGED: host_status = DID_BAD_TARGET; break; case CS_QUEUE_FULL: host_status = DID_ERROR; break; default: printk("qlogicfc : unknown completion status 0x%04x\n", le16_to_cpu(sts->completion_status)); host_status = DID_ERROR; break; } DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n", reason[host_status], le16_to_cpu(sts->scsi_status))); LEAVE("isp2x00_return_status"); return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16);}int isp2x00_abort(Scsi_Cmnd * Cmnd){ u_short param[8]; int i; struct Scsi_Host *host; struct isp2x00_hostdata *hostdata; int return_status = SUCCESS; ENTER("isp2x00_abort"); host = Cmnd->host; hostdata = (struct isp2x00_hostdata *) host->hostdata; for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++) if (hostdata->handle_ptrs[i] == Cmnd) break; if (i == QLOGICFC_REQ_QUEUE_LEN){ return SUCCESS; } isp2x00_disable_irqs(host); param[0] = MBOX_ABORT_IOCB;#if ISP2x00_PORTDB param[1] = (((u_short) hostdata->port_db[Cmnd->target].loop_id) << 8) | Cmnd->lun;#else param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun;#endif param[2] = i & 0xffff; param[3] = i >> 16; isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d : scsi abort failure: %x\n", hostdata->host_id, param[0]); if (param[0] == 0x4005) Cmnd->result = DID_ERROR << 16; if (param[0] == 0x4006) Cmnd->result = DID_BAD_TARGET << 16; return_status = FAILED; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -