nsp32.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,409 行 · 第 1/5 页
C
2,409 行
unsigned char target = SCpnt->device->id; nsp32_autoparam *param = data->autoparam; unsigned char phase; int i, ret; unsigned int msgout; u16_le s; nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in"); /* * check bus free */ phase = nsp32_read1(base, SCSI_BUS_MONITOR); if (phase != BUSMON_BUS_FREE) { nsp32_msg(KERN_WARNING, "bus busy"); show_busphase(phase & BUSMON_PHASE_MASK); SCpnt->result = DID_BUS_BUSY << 16; return FALSE; } /* * message out * * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout. * over 3 messages needs another routine. */ if (data->msgout_len == 0) { nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!"); SCpnt->result = DID_ERROR << 16; return FALSE; } else if (data->msgout_len > 0 && data->msgout_len <= 3) { msgout = 0; for (i = 0; i < data->msgout_len; i++) { /* * the sending order of the message is: * MCNT 3: MSG#0 -> MSG#1 -> MSG#2 * MCNT 2: MSG#1 -> MSG#2 * MCNT 1: MSG#2 */ msgout >>= 8; msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24); } msgout |= MV_VALID; /* MV valid */ msgout |= (unsigned int)data->msgout_len; /* len */ } else { /* data->msgout_len > 3 */ msgout = 0; } // nsp_dbg(NSP32_DEBUG_AUTOSCSI, "sel time out=0x%x\n", nsp32_read2(base, SEL_TIME_OUT)); // nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); /* * setup asic parameter */ memset(param, 0, sizeof(nsp32_autoparam)); /* cdb */ for (i = 0; i < SCpnt->cmd_len; i++) { param->cdb[4 * i] = SCpnt->cmnd[i]; } /* outgoing messages */ param->msgout = cpu_to_le32(msgout); /* syncreg, ackwidth, target id, SREQ sampling rate */ param->syncreg = data->cur_target->syncreg; param->ackwidth = data->cur_target->ackwidth; param->target_id = BIT(host_id) | BIT(target); param->sample_reg = data->cur_target->sample_reg; // nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "sample rate=0x%x\n", data->cur_target->sample_reg); /* command control */ param->command_control = cpu_to_le16(CLEAR_CDB_FIFO_POINTER | AUTOSCSI_START | AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02 | AUTO_ATN ); /* transfer control */ s = 0; switch (data->trans_method) { case NSP32_TRANSFER_BUSMASTER: s |= BM_START; break; case NSP32_TRANSFER_MMIO: s |= CB_MMIO_MODE; break; case NSP32_TRANSFER_PIO: s |= CB_IO_MODE; break; default: nsp32_msg(KERN_ERR, "unknown trans_method"); break; } /* * OR-ed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits. * For bus master transfer, it's taken off. */ s |= (TRANSFER_GO | ALL_COUNTER_CLR); param->transfer_control = cpu_to_le16(s); /* sg table addr */ param->sgt_pointer = cpu_to_le32(data->cur_lunt->sglun_paddr); /* * transfer parameter to ASIC */ nsp32_write4(base, SGT_ADR, data->auto_paddr); nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER | AUTO_PARAMETER ); /* * Check arbitration */ ret = nsp32_arbitration(SCpnt, base); return ret;}/* * Selection with AUTO SCSI (without AUTO PARAMETER) */static int nsp32_selection_autoscsi(Scsi_Cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = SCpnt->device->host->io_port; unsigned int host_id = SCpnt->device->host->this_id; unsigned char target = SCpnt->device->id; unsigned char phase; int status; unsigned short command = 0; unsigned int msgout = 0; unsigned short execph; int i; nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in"); /* * IRQ disable */ nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); /* * check bus line */ phase = nsp32_read1(base, SCSI_BUS_MONITOR); if(((phase & BUSMON_BSY) == 1) || (phase & BUSMON_SEL) == 1) { nsp32_msg(KERN_WARNING, "bus busy"); SCpnt->result = DID_BUS_BUSY << 16; status = 1; goto out; } /* * clear execph */ execph = nsp32_read2(base, SCSI_EXECUTE_PHASE); /* * clear FIFO counter to set CDBs */ nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER); /* * set CDB0 - CDB15 */ for (i = 0; i < SCpnt->cmd_len; i++) { nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]); } nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[0]); /* * set SCSIOUT LATCH(initiator)/TARGET(target) (OR-ed) ID */ nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID, BIT(host_id) | BIT(target)); /* * set SCSI MSGOUT REG * * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout. * over 3 messages needs another routine. */ if (data->msgout_len == 0) { nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!"); SCpnt->result = DID_ERROR << 16; status = 1; goto out; } else if (data->msgout_len > 0 && data->msgout_len <= 3) { msgout = 0; for (i = 0; i < data->msgout_len; i++) { /* * the sending order of the message is: * MCNT 3: MSG#0 -> MSG#1 -> MSG#2 * MCNT 2: MSG#1 -> MSG#2 * MCNT 1: MSG#2 */ msgout >>= 8; msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24); } msgout |= MV_VALID; /* MV valid */ msgout |= (unsigned int)data->msgout_len; /* len */ nsp32_write4(base, SCSI_MSG_OUT, msgout); } else { /* data->msgout_len > 3 */ nsp32_write4(base, SCSI_MSG_OUT, 0); } /* * set selection timeout(= 250ms) */ nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); /* * set SREQ hazard killer sampling rate * * TODO: sample_rate (BASE+0F) is 0 when internal clock = 40MHz. * check other internal clock! */ nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg); /* * clear Arbit */ nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); /* * set SYNCREG * Don't set BM_START_ADR before setting this register. */ nsp32_write1(base, SYNC_REG, data->cur_target->syncreg); /* * set ACKWIDTH */ nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth); nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x", nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH), nsp32_read4(base, SGT_ADR), nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID)); nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgout_len=%d, msgout=0x%x", data->msgout_len, msgout); /* * set SGT ADDR (physical address) */ nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr); /* * set TRANSFER CONTROL REG */ command = 0; command |= (TRANSFER_GO | ALL_COUNTER_CLR); if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { if (SCpnt->request_bufflen > 0) { command |= BM_START; } } else if (data->trans_method & NSP32_TRANSFER_MMIO) { command |= CB_MMIO_MODE; } else if (data->trans_method & NSP32_TRANSFER_PIO) { command |= CB_IO_MODE; } nsp32_write2(base, TRANSFER_CONTROL, command); /* * start AUTO SCSI, kick off arbitration */ command = (CLEAR_CDB_FIFO_POINTER | AUTOSCSI_START | AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02 | AUTO_ATN ); nsp32_write2(base, COMMAND_CONTROL, command); /* * Check arbitration */ status = nsp32_arbitration(SCpnt, base); out: /* * IRQ enable */ nsp32_write2(base, IRQ_CONTROL, 0); return status;}/* * Arbitration Status Check * * Note: Arbitration counter is waited during ARBIT_GO is not lifting. * Using udelay(1) consumes CPU time and system time, but * arbitration delay time is defined minimal 2.4us in SCSI * specification, thus udelay works as coarse grained wait timer. */static int nsp32_arbitration(Scsi_Cmnd *SCpnt, unsigned int base){ unsigned char arbit; int status = TRUE; int time = 0; do { arbit = nsp32_read1(base, ARBIT_STATUS); time++; } while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && (time <= ARBIT_TIMEOUT_TIME)); nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit: 0x%x, delay time: %d", arbit, time); if (arbit & ARBIT_WIN) { /* Arbitration succeeded */ SCpnt->result = DID_OK << 16; nsp32_index_write1(base, EXT_PORT, LED_ON); /* PCI LED on */ } else if (arbit & ARBIT_FAIL) { /* Arbitration failed */ SCpnt->result = DID_BUS_BUSY << 16; status = FALSE; } else { /* * unknown error or ARBIT_GO timeout, * something lock up! guess no connection. */ nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit timeout"); SCpnt->result = DID_NO_CONNECT << 16; status = FALSE; } /* * clear Arbit */ nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); return status;}/* * reselection * * Note: This reselection routine is called from msgin_occur, * reselection target id&lun must be already set. * SCSI-2 says IDENTIFY implies RESTORE_POINTER operation. */static int nsp32_reselection(Scsi_Cmnd *SCpnt, unsigned char newlun){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int host_id = SCpnt->device->host->this_id; unsigned int base = SCpnt->device->host->io_port; unsigned char tmpid, newid; nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter"); /* * calculate reselected SCSI ID */ tmpid = nsp32_read1(base, RESELECT_ID); tmpid &= (~BIT(host_id)); newid = 0; while (tmpid) { if (tmpid & 1) { break; } tmpid >>= 1; newid++; } /* * If reselected New ID:LUN is not existed * or current nexus is not existed, unexpected * reselection is occurred. Send reject message. */ if (newid >= ARRAY_SIZE(data->lunt) || newlun >= ARRAY_SIZE(data->lunt[0])) { nsp32_msg(KERN_WARNING, "unknown id/lun"); return FALSE; } else if(data->lunt[newid][newlun].SCpnt == NULL) { nsp32_msg(KERN_WARNING, "no SCSI command is processing"); return FALSE; } data->cur_id = newid; data->cur_lun = newlun; data->cur_target = &(data->target[newid]); data->cur_lunt = &(data->lunt[newid][newlun]); /* reset SACK/SavedACK counter (or ALL clear?) */ nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); return TRUE;}/* * nsp32_setup_sg_table - build scatter gather list for transfer data * with bus master. * * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time. */static int nsp32_setup_sg_table(Scsi_Cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; struct scatterlist *sgl; nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt; int num, i; u32_le l; if (SCpnt->request_bufflen == 0) { return TRUE; } if (sgt == NULL) { nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null"); return FALSE; } if (SCpnt->use_sg) { sgl = (struct scatterlist *)SCpnt->request_buffer; num = pci_map_sg(data->Pci, sgl, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); for (i = 0; i < num; i++) { /* * Build nsp32_sglist, substitute sg dma addresses. */ sgt[i].addr = cpu_to_le32(sg_dma_address(sgl)); sgt[i].len = cpu_to_le32(sg_dma_len(sgl)); sgl++; if (le32_to_cpu(sgt[i].len) > 0x10000) { nsp32_msg(KERN_ERR, "can't transfer over 64KB at a time, size=0x%lx", le32_to_cpu(sgt[i].len)); return FALSE; } nsp32_dbg(NSP32_DEBUG_SGLIST, "num 0x%x : addr 0x%lx len 0x%lx", i, le32_to_cpu(sgt[i].addr), le32_to_cpu(sgt[i].len )); } /* set end mark */ l = le32_to_cpu(sgt[num-1].len); sgt[num-1].len = cpu_to_le32(l | SGTEND); } else { SCpnt->SCp.have_data_in = pci_map_single(data->Pci, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); sgt[0].addr = cpu_to_le32(SCpnt->SCp.have_data_in); sgt[0].len = cpu_to_le32(SCpnt->request_bufflen | SGTEND); /* set end mark */ if (SCpnt->request_bufflen > 0x10000) { nsp32_msg(KERN_ERR, "can't transfer over 64KB at a time, size=0x%lx", SCpnt->request_bufflen); return FALSE; } nsp32_dbg(NSP32_DEBUG_SGLIST, "single : addr 0x%lx len=0x%lx", le32_to_cpu(sgt[0].addr), le32_to_cpu(sgt[0].len )); } return TRUE;}static int nsp32_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; nsp32_target *target; nsp32_lunt *cur_lunt; int ret; nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "enter. target: 0x%x LUN: 0x%x cmnd: 0x%x cmndlen: 0x%x " "use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x", SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_buffer, SCpnt->request_bufflen);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?