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

📄 acornscsi.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",		host->host->host_no, acornscsi_target(host));	return 0;    }    residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred;    sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);    sbic_arm_writenext(host->scsi.io_port, residual >> 16);    sbic_arm_writenext(host->scsi.io_port, residual >> 8);    sbic_arm_writenext(host->scsi.io_port, residual);    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);    return 1;}/* ========================================================================================= * Connection & Disconnection *//* * Function : acornscsi_reconnect(AS_Host *host) * Purpose  : reconnect a previously disconnected command * Params   : host - host specific data * Remarks  : SCSI spec says: *		'The set of active pointers is restored from the set *		 of saved pointers upon reconnection of the I/O process' */staticint acornscsi_reconnect(AS_Host *host){    unsigned int target, lun, ok = 0;    target = sbic_arm_read(host->scsi.io_port, SBIC_SOURCEID);    if (!(target & 8))	printk(KERN_ERR "scsi%d: invalid source id after reselection "		"- device fault?\n",		host->host->host_no);    target &= 7;    if (host->SCpnt && !host->scsi.disconnectable) {	printk(KERN_ERR "scsi%d.%d: reconnected while command in "		"progress to target %d?\n",		host->host->host_no, target, host->SCpnt->device->id);	host->SCpnt = NULL;    }    lun = sbic_arm_read(host->scsi.io_port, SBIC_DATA) & 7;    host->scsi.reconnected.target = target;    host->scsi.reconnected.lun = lun;    host->scsi.reconnected.tag = 0;    if (host->scsi.disconnectable && host->SCpnt &&	host->SCpnt->device->id == target && host->SCpnt->device->lun == lun)	ok = 1;    if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun))	ok = 1;    ADD_STATUS(target, 0x81, host->scsi.phase, 0);    if (ok) {	host->scsi.phase = PHASE_RECONNECTED;    } else {	/* this doesn't seem to work */	printk(KERN_ERR "scsi%d.%c: reselected with no command "		"to reconnect with\n",		host->host->host_no, '0' + target);	acornscsi_dumplog(host, target);	acornscsi_abortcmd(host, 0);	if (host->SCpnt) {	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);	    host->SCpnt = NULL;	}    }    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);    return !ok;}/* * Function: int acornscsi_reconect_finish(AS_Host *host) * Purpose : finish reconnecting a command * Params  : host - host to complete * Returns : 0 if failed */staticint acornscsi_reconnect_finish(AS_Host *host){    if (host->scsi.disconnectable && host->SCpnt) {	host->scsi.disconnectable = 0;	if (host->SCpnt->device->id  == host->scsi.reconnected.target &&	    host->SCpnt->device->lun == host->scsi.reconnected.lun &&	    host->SCpnt->tag         == host->scsi.reconnected.tag) {#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))	    DBG(host->SCpnt, printk("scsi%d.%c: reconnected",		    host->host->host_no, acornscsi_target(host)));#endif	} else {	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))	    DBG(host->SCpnt, printk("scsi%d.%c: had to move command "		    "to disconnected queue\n",		    host->host->host_no, acornscsi_target(host)));#endif	    host->SCpnt = NULL;	}    }    if (!host->SCpnt) {	host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected,				host->scsi.reconnected.target,				host->scsi.reconnected.lun,				host->scsi.reconnected.tag);#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))	DBG(host->SCpnt, printk("scsi%d.%c: had to get command",		host->host->host_no, acornscsi_target(host)));#endif    }    if (!host->SCpnt)	acornscsi_abortcmd(host, host->scsi.reconnected.tag);    else {	/*	 * Restore data pointer from SAVED pointers.	 */	host->scsi.SCp = host->SCpnt->SCp;#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))	printk(", data pointers: [%p, %X]",		host->scsi.SCp.ptr, host->scsi.SCp.this_residual);#endif    }#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))    printk("\n");#endif    host->dma.transferred = host->scsi.SCp.scsi_xferred;    return host->SCpnt != NULL;}/* * Function: void acornscsi_disconnect_unexpected(AS_Host *host) * Purpose : handle an unexpected disconnect * Params  : host - host on which disconnect occurred */staticvoid acornscsi_disconnect_unexpected(AS_Host *host){    printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n",	    host->host->host_no, acornscsi_target(host));#if (DEBUG & DEBUG_ABORT)    acornscsi_dumplog(host, 8);#endif    acornscsi_done(host, &host->SCpnt, DID_ERROR);}/* * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag) * Purpose : abort a currently executing command * Params  : host - host with connected command to abort *	     tag  - tag to abort */staticvoid acornscsi_abortcmd(AS_Host *host, unsigned char tag){    host->scsi.phase = PHASE_ABORTED;    sbic_arm_write(host->scsi.io_port, SBIC_CMND, CMND_ASSERTATN);    msgqueue_flush(&host->scsi.msgs);#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE    if (tag)	msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag);    else#endif	msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);}/* ========================================================================================== * Interrupt routines. *//* * Function: int acornscsi_sbicintr(AS_Host *host) * Purpose : handle interrupts from SCSI device * Params  : host - host to process * Returns : INTR_PROCESS if expecting another SBIC interrupt *	     INTR_IDLE if no interrupt *	     INTR_NEXT_COMMAND if we have finished processing the command */staticintr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq){    unsigned int asr, ssr;    asr = sbic_arm_read(host->scsi.io_port, SBIC_ASR);    if (!(asr & ASR_INT))	return INTR_IDLE;    ssr = sbic_arm_read(host->scsi.io_port, SBIC_SSR);#if (DEBUG & DEBUG_PHASES)    print_sbic_status(asr, ssr, host->scsi.phase);#endif    ADD_STATUS(8, ssr, host->scsi.phase, in_irq);    if (host->SCpnt && !host->scsi.disconnectable)	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);    switch (ssr) {    case 0x00:				/* reset state - not advanced			*/	printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",		host->host->host_no);	/* setup sbic - WD33C93A */	sbic_arm_write(host->scsi.io_port, SBIC_OWNID, OWNID_EAF | host->host->this_id);	sbic_arm_write(host->scsi.io_port, SBIC_CMND, CMND_RESET);	return INTR_IDLE;    case 0x01:				/* reset state - advanced			*/	sbic_arm_write(host->scsi.io_port, SBIC_CTRL, INIT_SBICDMA | CTRL_IDI);	sbic_arm_write(host->scsi.io_port, SBIC_TIMEOUT, TIMEOUT_TIME);	sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, SYNCHTRANSFER_2DBA);	sbic_arm_write(host->scsi.io_port, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);	msgqueue_flush(&host->scsi.msgs);	return INTR_IDLE;    case 0x41:				/* unexpected disconnect aborted command	*/	acornscsi_disconnect_unexpected(host);	return INTR_NEXT_COMMAND;    }    switch (host->scsi.phase) {    case PHASE_CONNECTING:		/* STATE: command removed from issue queue	*/	switch (ssr) {	case 0x11:			/* -> PHASE_CONNECTED				*/	    /* BUS FREE -> SELECTION */	    host->scsi.phase = PHASE_CONNECTED;	    msgqueue_flush(&host->scsi.msgs);	    host->dma.transferred = host->scsi.SCp.scsi_xferred;	    /* 33C93 gives next interrupt indicating bus phase */	    asr = sbic_arm_read(host->scsi.io_port, SBIC_ASR);	    if (!(asr & ASR_INT))		break;	    ssr = sbic_arm_read(host->scsi.io_port, SBIC_SSR);	    ADD_STATUS(8, ssr, host->scsi.phase, 1);	    ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, 1);	    goto connected;	    	case 0x42:			/* select timed out				*/					/* -> PHASE_IDLE				*/	    acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT);	    return INTR_NEXT_COMMAND;	case 0x81:			/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/	    /* BUS FREE -> RESELECTION */	    host->origSCpnt = host->SCpnt;	    host->SCpnt = NULL;	    msgqueue_flush(&host->scsi.msgs);	    acornscsi_reconnect(host);	    break;	default:	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",		    host->host->host_no, acornscsi_target(host), ssr);	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);	    acornscsi_abortcmd(host, host->SCpnt->tag);	}	return INTR_PROCESSING;    connected:    case PHASE_CONNECTED:		/* STATE: device selected ok			*/	switch (ssr) {#ifdef NONSTANDARD	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/	    /* SELECTION -> COMMAND */	    acornscsi_sendcommand(host);	    break;	case 0x8b:			/* -> PHASE_STATUS				*/	    /* SELECTION -> STATUS */	    acornscsi_readstatusbyte(host);	    host->scsi.phase = PHASE_STATUSIN;	    break;#endif	case 0x8e:			/* -> PHASE_MSGOUT				*/	    /* SELECTION ->MESSAGE OUT */	    host->scsi.phase = PHASE_MSGOUT;	    acornscsi_buildmessages(host);	    acornscsi_sendmessage(host);	    break;	/* these should not happen */	case 0x85:			/* target disconnected				*/	    acornscsi_done(host, &host->SCpnt, DID_ERROR);	    break;	default:	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",		    host->host->host_no, acornscsi_target(host), ssr);	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);	    acornscsi_abortcmd(host, host->SCpnt->tag);	}	return INTR_PROCESSING;    case PHASE_MSGOUT:			/* STATE: connected & sent IDENTIFY message	*/	/*	 * SCSI standard says that MESSAGE OUT phases can be followed by a	 * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase	 */	switch (ssr) {	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/	case 0x1a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/	    /* MESSAGE OUT -> COMMAND */	    acornscsi_sendcommand(host);	    break;	case 0x8b:			/* -> PHASE_STATUS				*/	case 0x1b:			/* -> PHASE_STATUS				*/	    /* MESSAGE OUT -> STATUS */	    acornscsi_readstatusbyte(host);	    host->scsi.phase = PHASE_STATUSIN;	    break;	case 0x8e:			/* -> PHASE_MSGOUT				*/	    /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */	    acornscsi_sendmessage(host);	    break;	case 0x4f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/	    /* MESSAGE OUT -> MESSAGE IN */	    acornscsi_message(host);	    break;	default:	    printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",		    host->host->host_no, acornscsi_target(host), ssr);	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);	}	return INTR_PROCESSING;    case PHASE_COMMAND: 		/* STATE: connected & command sent		*/	switch (ssr) {	case 0x18:			/* -> PHASE_DATAOUT				*/	    /* COMMAND -> DATA OUT */	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)		acornscsi_abortcmd(host, host->SCpnt->tag);	    acornscsi_dma_setup(host, DMA_OUT);	    if (!acornscsi_starttransfer(host))		acornscsi_abortcmd(host, host->SCpnt->tag);	    host->scsi.phase = PHASE_DATAOUT;	    return INTR_IDLE;	case 0x19:			/* -> PHASE_DATAIN				*/	    /* COMMAND -> DATA IN */	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)		acornscsi_abortcmd(host, host->SCpnt->tag);	    acornscsi_dma_setup(host, DMA_IN);	    if (!acornscsi_starttransfer(host))		acornscsi_abortcmd(host, host->SCpnt->tag);	    host->scsi.phase = PHASE_DATAIN;	    return INTR_IDLE;	case 0x1b:			/* -> PHASE_STATUS				*/	    /* COMMAND -> STATUS */	    acornscsi_readstatusbyte(host);	    host->scsi.phase = PHASE_STATUSIN;	    break;	case 0x1e:			/* -> PHASE_MSGOUT				*/	    /* COMMAND -> MESSAGE OUT */	    acornscsi_sendmessage(host);	    break;	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/	    /* COMMAND -> MESSAGE IN */	    acornscsi_message(host);	    break;	default:	    printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",		    host->host->host_no, acornscsi_target(host), ssr);	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);	}	return INTR_PROCESSING;    case PHASE_DISCONNECT:		/* STATE: connected, received DISCONNECT msg	*/	if (ssr == 0x85) {		/* -> PHASE_IDLE				*/	    host->scsi.disconnectable = 1;	    host->scsi.reconnected.tag = 0;	    host->scsi.phase = PHASE_IDLE;	    host->stats.disconnects += 1;	} else {	    printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",		    host->host->host_no, acornscsi_target(host), ssr);	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);	}	return INTR_NEXT_COMMAND;    case PHASE_IDLE:			/* STATE: disconnected				*/	if (ssr == 0x81)		/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/	    acornscsi_reconnect(host);	else {	    printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",		    host->host->host_no, acornscsi_target(host), ssr);	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);	}	return INTR_PROCESSING;    case PHASE_RECONNECTED:		/* STATE: device reconnected to initiator	*/	/*	 * Command reconnected - if MESGIN, get message - it may be	 * the tag.  If not, get command out of disconnected queue	 */	/*	 * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY,	 * reconnect I_T_L command	 */	if (ssr != 0x8f && !acornscsi_reconnect_finish(host))	    return INTR_IDLE;	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);	switch (ssr) {	case 0x88:			/* data out phase				*/					/* -> PHASE_DATAOUT				*/	    /* MESSAGE IN -> DATA OUT */	    acornscsi_dma_setup(host, DMA_OUT);	    if (!acornscsi_starttransfer(host))		acornscsi_abortcmd(host, host->SCpnt->tag);	    host->scsi.phase = PHASE_DATAOUT;	    return INTR_IDLE;	case 0x89:			/* data in phase				*/					/* -> PHASE_DATAIN				*/	    /* MESSAGE IN -> DATA IN */	    acornscsi_dma_setup(host, DMA_IN);	    if (!acornscsi_starttransfer(host))		acornscsi_abortcmd(host, host->SCpnt->tag);	    host->scsi.phase = PHASE_DATAIN;	    return INTR_IDLE;	case 0x8a:			/* command out					*/	    /* MESSAG

⌨️ 快捷键说明

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