⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sim710.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		DIEN_ABRT | DIEN_SSI | DIEN_SIR | DIEN_700_OPC);    NCR_write8(SIEN_REG_700,	    SIEN_PAR | SIEN_700_STO | SIEN_RST | SIEN_UDC | SIEN_SGE | SIEN_MA);#ifdef CONFIG_TP34V_SCSI    tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x30 | TP34V_SCSI0n1_IPL;#endif    restore_flags(flags);}/* * Function : static void sim710_driver_init (struct Scsi_Host *host) * * Purpose : Initialize internal structures, as required on startup, or *	after a SCSI bus reset. * * Inputs : host - pointer to this host adapter's structure */static voidsim710_driver_init (struct Scsi_Host *host){    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)	host->hostdata[0];    int i;    hostdata->running = NULL;    memcpy (hostdata->script, SCRIPT, sizeof(SCRIPT));    for (i = 0; i < PATCHES; i++)	hostdata->script[LABELPATCHES[i]] += virt_to_bus(hostdata->script);    patch_abs_32 (hostdata->script, 0, reselected_identify,     	virt_to_bus((void *)&(hostdata->reselected_identify)));    patch_abs_32 (hostdata->script, 0, msgin_buf,     	virt_to_bus((void *)&(hostdata->msgin_buf[0])));    hostdata->state = STATE_INITIALISED;    hostdata->negotiate = 0xff;}/* Handle incoming Synchronous data transfer request.  If our negotiate * flag is set then this is a response to our request, otherwise it is * spurious request from the target.  Don't really expect target initiated * SDTRs, because we always negotiate on the first command.  Could still * get them though.. * The chip is currently paused with ACK asserted o the last byte of the * SDTR. * resa is the resume address if the message is in response to our outgoing * SDTR.  Only possible on initial identify. * resb is the resume address if the message exchange is initiated by the * target. */static u32handle_sdtr (struct Scsi_Host * host, Scsi_Cmnd * cmd, u32 resa, u32 resb){    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];    struct sim710_target *targdata = hostdata->target + cmd->target;    u32 resume_offset;    if (resa && hostdata->negotiate & (1 << cmd->target)) {	DEB(DEB_SYNC, printk("scsi%d: Response to host SDTR = %02x %02x\n",		host->host_no, hostdata->msgin_buf[3], hostdata->msgin_buf[4]));	/* We always issue an SDTR with the identify, so we must issue	 * the CDB next.	 */	resume_offset = resa;	hostdata->negotiate &= ~(1 << cmd->target);    }    else {	DEB(DEB_SYNC, printk("scsi%d: Target initiated SDTR = %02x %02x\n",		host->host_no, hostdata->msgin_buf[3], hostdata->msgin_buf[4]));	memcpy(targdata->dsa_msgout, async_message, sizeof(async_message));	targdata->dsa[DSA_MSGOUT] = sizeof(async_message);	/* I guess the target could do this anytime; we have to send our	 * response, and then continue (sending the CDB if not already done).	 */	resume_offset = resb;    }    return resume_offset;}/* * Function : static int datapath_residual (Scsi_Host *host) * * Purpose : return residual data count of what's in the chip. * * Inputs : host - SCSI host */static intdatapath_residual (struct Scsi_Host *host) {    int count, synchronous, sstat;    unsigned int ddir;    count = ((NCR_read8 (DFIFO_REG) & DFIFO_10_BO_MASK) -	(NCR_read32 (DBC_REG) & DFIFO_10_BO_MASK)) & DFIFO_10_BO_MASK;    synchronous = NCR_read8 (SXFER_REG) & SXFER_MO_MASK;    ddir = NCR_read8 (CTEST0_REG_700) & CTEST0_700_DDIR;    if (ddir) {    /* Receive */	if (synchronous) 	    count += (NCR_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;	else	    if (NCR_read8 (SSTAT1_REG) & SSTAT1_ILF)		++count;    } else {    /* Send */	sstat = NCR_read8 (SSTAT1_REG);	if (sstat & SSTAT1_OLF)	    ++count;	if (synchronous && (sstat & SSTAT1_ORF))	    ++count;    }    return count;}static u32handle_idd (struct Scsi_Host * host, Scsi_Cmnd * cmd){    struct sim710_hostdata *hostdata =		(struct sim710_hostdata *)host->hostdata[0];    struct sim710_target *targdata = hostdata->target + cmd->target;    u32 resume_offset = 0, index;    index = (u32)((u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script);    switch (index) {    case Ent_wait_disc_complete/4 + 2:	cmd->result = targdata->dsa_status[0];        SCSI_DONE(cmd);	targdata->cur_cmd = NULL;	resume_offset = Ent_reselect;	break;    case Ent_wait_disc2/4 + 2:	/* Disconnect after command - just wait for a reselect */	targdata->resume_offset = Ent_resume_msgin2a;	resume_offset = Ent_reselect;	break;    case Ent_wait_disc3/4 + 2:	/* Disconnect after the data phase */	targdata->resume_offset = Ent_resume_msgin3a;	resume_offset = Ent_reselect;	break;    case Ent_wait_disc1/4 + 2:	/* Disconnect before command - not expected */	targdata->resume_offset = Ent_resume_msgin1a;	resume_offset = Ent_reselect;	break;    default:	printk("scsi%d: Unexpected Illegal Instruction, script[%04x]\n",		host->host_no, index);	sim710_errors++;	/* resume_offset is zero, which will cause host reset */    }    return resume_offset;}/* Handle a phase mismatch. */static u32handle_phase_mismatch (struct Scsi_Host * host, Scsi_Cmnd * cmd){    struct sim710_hostdata *hostdata =		(struct sim710_hostdata *)host->hostdata[0];    struct sim710_target *targdata = hostdata->target + cmd->target;    u32 resume_offset = 0, index;    unsigned char sbcl;    sbcl = NCR_read8(SBCL_REG) & SBCL_PHASE_MASK;    index = (u32)((u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script);    DEB(DEB_PMM, printk("scsi%d: Phase mismatch, phase %s (%x) at script[0x%x]\n",	host->host_no, sbcl_to_phase(sbcl), sbcl, index));    DEB(DEB_PMM, print_command(cmd->cmnd));    if (index == Ent_done_ident/4) {	/* Sending initial message out - probably rejecting our sync	 * negotiation request.	 */	NCR_write8(SOCL_REG, 0);	/* Negate ATN */	if (sbcl == SBCL_PHASE_MSGIN)	    resume_offset = Ent_resume_rej_ident;	else if (sbcl == SBCL_PHASE_CMDOUT) {	    /* Some old devices (SQ555) switch to cmdout after the first	     * byte of an identify message, regardless of whether we	     * have more bytes to send!	     */	    printk("scsi%d: Unexpected switch to CMDOUT during IDENTIFY\n",		host->host_no);	    resume_offset = Ent_resume_cmd;	}	else {	    printk("scsi%d: Unexpected phase change to %s on initial msgout\n",		host->host_no, sbcl_to_phase(sbcl));	    /* resume_offset is zero, which will cause a host reset */	}	hostdata->negotiate &= ~(1 << cmd->target);    }    else if (index > Ent_patch_input_data/4 &&		index < Ent_patch_output_data/4) {	/* DataIn transfer phase */	u32 sg_id, oaddr, olen, naddr, nlen;	int residual;	sg_id = (index - Ent_patch_input_data/4 - 4) / 2;	targdata->data_in_jump = hostdata->script[Ent_patch_input_data/4+1] =		virt_to_bus(hostdata->script + Ent_patch_input_data/4 + sg_id * 2 + 2);	olen  = targdata->dsa[DSA_DATAIN + sg_id * 2];	oaddr = targdata->dsa[DSA_DATAIN + sg_id * 2 + 1];	residual = datapath_residual (host);	if (residual)	    printk("scsi%d: Residual count %d on DataIn - NOT expected!!!",		host->host_no, residual);	naddr = NCR_read32(DNAD_REG) - residual;	nlen  = (NCR_read32(DBC_REG) & 0x00ffffff) + residual;	DEB(DEB_PMM, printk("scsi%d: DIN sg %d, old %08x/%08x, new %08x/%08x (%d)\n",		host->host_no, sg_id, oaddr, olen, naddr, nlen, residual));	if (oaddr+olen != naddr+nlen) {	    printk("scsi%d: PMM DIN counts error: 0x%x + 0x%x != 0x%x + 0x%x",		host->host_no, oaddr, olen, naddr, nlen);	}	else {	    targdata->dsa[DSA_DATAIN + sg_id * 2]     = nlen;	    targdata->dsa[DSA_DATAIN + sg_id * 2 + 1] = naddr;	    resume_offset = Ent_resume_pmm;	}    }    else if (index > Ent_patch_output_data/4 &&		index <= Ent_end_data_trans/4) {	/* Dataout transfer phase */	u32 sg_id, oaddr, olen, naddr, nlen;	int residual;	sg_id = (index - Ent_patch_output_data/4 - 4) / 2;	targdata->data_out_jump = hostdata->script[Ent_patch_output_data/4+1] =		virt_to_bus(hostdata->script + Ent_patch_output_data/4 + sg_id * 2 + 2);	olen  = targdata->dsa[DSA_DATAOUT + sg_id * 2];	oaddr = targdata->dsa[DSA_DATAOUT + sg_id * 2 + 1];	residual = datapath_residual (host);	naddr = NCR_read32(DNAD_REG) - residual;	nlen  = (NCR_read32(DBC_REG) & 0x00ffffff) + residual;	DEB(DEB_PMM, printk("scsi%d: DOUT sg %d, old %08x/%08x, new %08x/%08x (%d)\n",		host->host_no, sg_id, oaddr, olen, naddr, nlen, residual));	if (oaddr+olen != naddr+nlen) {	    printk("scsi%d: PMM DOUT counts error: 0x%x + 0x%x != 0x%x + 0x%x",		host->host_no, oaddr, olen, naddr, nlen);	}	else {	    targdata->dsa[DSA_DATAOUT + sg_id * 2]     = nlen;	    targdata->dsa[DSA_DATAOUT + sg_id * 2 + 1] = naddr;	    resume_offset = Ent_resume_pmm;	}    }    else {	printk("scsi%d: Unexpected phase change to %s at index 0x%x\n",		host->host_no, sbcl_to_phase(sbcl), index);	/* resume_offset is zero, which will cause a host reset */    }    /* Flush DMA FIFO */    NCR_write8 (CTEST8_REG, CTEST8_10_CLF);    while (NCR_read8 (CTEST8_REG) & CTEST8_10_CLF);    return resume_offset;}static u32handle_script_int(struct Scsi_Host * host, Scsi_Cmnd * cmd){    struct sim710_hostdata *hostdata =		(struct sim710_hostdata *)host->hostdata[0];    struct sim710_target *targdata = hostdata->target + cmd->target;    u32 dsps, resume_offset = 0;    unsigned char sbcl;    dsps = NCR_read32(DSPS_REG);    switch (dsps) {    case A_int_cmd_complete:	cmd->result = targdata->dsa_status[0];        SCSI_DONE(cmd);	targdata->cur_cmd = NULL;	resume_offset = Ent_reselect;	break;    case A_int_msg_sdtr1:	resume_offset = handle_sdtr(host, cmd,		Ent_resume_msgin1a, Ent_resume_msgin1b);	break;    case A_int_msg_sdtr2:	resume_offset = handle_sdtr(host, cmd, 0, Ent_resume_msgin2b);	break;    case A_int_msg_sdtr3:	resume_offset = handle_sdtr(host, cmd, 0, Ent_resume_msgin3b);	break;    case A_int_disc1:	/* Disconnect before command - not expected */	targdata->resume_offset = Ent_resume_msgin1a;	resume_offset = Ent_reselect;	break;    case A_int_disc2:	/* Disconnect after command - just wait for a reselect */	targdata->resume_offset = Ent_resume_msgin2a;	resume_offset = Ent_reselect;	break;    case A_int_disc3:	/* Disconnect after the data phase */	targdata->resume_offset = Ent_resume_msgin3a;	resume_offset = Ent_reselect;	break;    case A_int_reselected:	hostdata->script[Ent_patch_output_data/4+1] = targdata->data_out_jump;	hostdata->script[Ent_patch_input_data/4+1] = targdata->data_in_jump;	NCR_write32(DSA_REG, virt_to_bus(targdata->dsa));	resume_offset = targdata->resume_offset;	break;    case A_int_data_bad_phase:	sbcl = NCR_read8(SBCL_REG) & SBCL_PHASE_MASK;	printk("scsi%d: int_data_bad_phase, phase %s (%x)\n",		host->host_no, sbcl_to_phase(sbcl), sbcl);	break;    case A_int_bad_extmsg1a:    case A_int_bad_extmsg1b:    case A_int_bad_extmsg2a:    case A_int_bad_extmsg2b:    case A_int_bad_extmsg3a:    case A_int_bad_extmsg3b:    case A_int_bad_msg1:    case A_int_bad_msg2:    case A_int_bad_msg3:    case A_int_cmd_bad_phase:    case A_int_no_msgout1:    case A_int_no_msgout2:    case A_int_no_msgout3:    case A_int_not_cmd_complete:    case A_int_sel_no_ident:    case A_int_sel_not_cmd:    case A_int_status_not_msgin:    case A_int_resel_not_msgin:    case A_int_selected:    case A_int_not_rej:    default:	sbcl = NCR_read8(SBCL_REG) & SBCL_PHASE_MASK;	printk("scsi%d: Unimplemented script interrupt: %08x, phase %s\n",		host->host_no, dsps, sbcl_to_phase(sbcl));	sim710_errors++;	/* resume_offset is zero, which will cause a host reset */    }    return resume_offset;}/* A quick wrapper for sim710_intr_handle to grab the spin lock */static voiddo_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs){    unsigned long flags;    spin_lock_irqsave(&io_request_lock, flags);    sim710_intr_handle(irq, dev_id, regs);    spin_unlock_irqrestore(&io_request_lock, flags);}/* A "high" level interrupt handler */static voidsim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs){    unsigned int flags;    struct Scsi_Host * host = (struct Scsi_Host *)dev_id;    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];    Scsi_Cmnd * cmd;    unsigned char istat, dstat;    unsigned char sstat0;    u32 dsps, resume_offset = 0;    save_flags(flags);    cli();    sim710_intrs++;    while ((istat = NCR_read8(ISTAT_REG)) & (ISTAT_SIP|ISTAT_DIP)) {	dsps = NCR_read32(DSPS_REG);	hostdata->state = STATE_HALTED;	sstat0 = dstat = 0;	if (istat & ISTAT_SIP) {	    sstat0 = NCR_read8(SSTAT0_REG);	}	if (istat & ISTAT_DIP) {	    udelay(10);		/* Some comment somewhere about 10cycles				 * between accesses to sstat0 and dstat ??? */	    dstat = NCR_read8(DSTAT_REG);	}	DEB(DEB_INTS, printk("scsi%d: Int %d, istat %02x, sstat0 %02x "		"dstat %02x, dsp [%04x], scratch %02x\n",	    host->host_no, sim710_intrs, istat, sstat0, dstat,	    (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script,	    NCR_read32(SCRATCH_REG)));	if ((dstat & DSTAT_SIR) && dsps == A_int_reselected) {	    /* Reselected.  Identify the target from LCRC_REG, and	     * update current command.  If we were trying to select	     * a device, then that command needs to go back on the	     * issue_queue for later.	     */	    unsigned char lcrc = NCR_read8(LCRC_REG_10);	    int id = 0;	    if (!(lcrc & 0x7f)) {		printk("scsi%d: Reselected with LCRC = %02x\n",			host->host_no, lcrc);		cmd = NULL;	    }	    else {		while (!(lcrc & 1)) {		    id++;		    lcrc >>= 1;		}		DEB(DEB_DISC, printk("scsi%d: Reselected by ID %d\n",			host->host_no, id));		if (hostdata->running) {		    /* Clear SIGP */		    (void)NCR_read8(CTEST2_REG_700);		    DEB(DEB_DISC, printk("scsi%d: Select of %d interrupted "				"by reselect from %d (%p)\n",				host->host_no, hostdata->running->target,				id, hostdata->target[id].cur_cmd));		    cmd = hostdata->running;		    hostdata->target[cmd->target].cur_cmd = NULL;		    cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;		    hostdata->issue_queue = cmd;		}		cmd = hostdata->running = hostdata->target[id].cur_cmd;	    }	}	else	    cmd = hostdata->running;	if (!cmd) {	    printk("scsi%d: No active command!\n", host->host_no);	    printk("scsi%d: Int %d, istat %02x, sstat0 %02x "		"dstat %02x, dsp [%04x], scratch %02x, dsps %08x\n",		host->host_no, sim710_intrs, istat, sstat0, dstat,		(u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script,		NCR_read32(SCRATCH_REG), dsps);	    /* resume_offset is zero, which will cause a host reset */	}	else if (sstat0 & SSTAT0_700_STO) {	    DEB(DEB_TOUT, printk("scsi%d: Selection timeout\n", host->host_no));	    cmd->result = DID_NO_CONNECT << 16;	    SCSI_DONE(cmd);	    hostdata->target[cmd->target].cur_cmd = NULL;	    resume_offset = Ent_reselect;	}	else if (dstat & DSTAT_SIR)	    resume_offset = handle_script_int(host, cmd);	else if (sstat0 & SSTAT0_MA) {	    resume_offset = handle_phase_mismatch(host, cmd);	}	else if (sstat0 & (SSTAT0_MA|SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) {	    printk("scsi%d: Serious error, sstat0 = %02x\n", host->host_no,			    sstat0);	    sim710_errors++;	    /* resume_offset is zero, which will cause a host reset */	}	else if (dstat & (DSTAT_BF|DSTAT_ABRT|DSTAT_SSI|DSTAT_WTD)) {	    printk("scsi%d: Serious error, dstat = %02x\n", host->host_no,			    dstat);	    sim710_errors++;	    /* resume_offset is zero, which will cause a host reset */	}	else if (dstat & DSTAT_IID) {	    /* This can be due to a quick reselect while doing a WAIT	     * DISCONNECT.	     */	    resume_offset = handle_idd(host, cmd);	}	else {	    sim710_errors++;	    printk("scsi%d: Spurious interrupt!\n", host->host_no);	    /* resume_offset is zero, which will cause a host reset */	}    }    if (resume_offset) {	if (resume_offset == Ent_reselect) {	    hostdata->running = NULL;	    hostdata->state = STATE_IDLE;	}	else	    hostdata->state = STATE_BUSY;	DEB(DEB_RESUME, printk("scsi%d: Resuming at script[0x%x]\n",		host->host_no, resume_offset/4));#ifdef DEBUG_LIMIT_INTS	if (sim710_intrs < DEBUG_LIMIT_INTS)#endif	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+resume_offset/4));	if (resume_offset == Ent_reselect)	    run_process_issue_queue(hostdata);    }    else {	printk("scsi%d: Failed to handle interrupt.  Failing commands "		"and resetting SCSI bus and chip\n", host->host_no);	mdelay(4000);		/* Give chance to read screen!! */	full_reset(host);    }    restore_flags(flags);}static voidrun_command (struct sim710_hostdata *hostdata, Scsi_Cmnd *cmd){    struct Scsi_Host *host = cmd->host;    struct sim710_target *targdata = hostdata->target + cmd->target;    int i, datain, dataout, sg_start;    u32 *dip, *dop, dsa;    DEB(DEB_CMND, printk("scsi%d: id%d starting ", host->host_no,		cmd->target));    DEB(DEB_CMND, print_command(cmd->cmnd));    switch (cmd->cmnd[0]) {    case INQUIRY:    case MODE_SENSE:    case READ_6:    case READ_10:    case READ_CAPACITY:    case REQUEST_SENSE:    case READ_BLOCK_LIMITS:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -