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

📄 acornscsi.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
    struct message *msg;#if (DEBUG & DEBUG_MESSAGES)    printk("scsi%d.%c: sending message ",	    host->host->host_no, acornscsi_target(host));#endif    switch (message_length) {    case 0:	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1");	sbic_arm_write(host->scsi.io_port, SBIC_DATA, NOP);	host->scsi.last_message = NOP;#if (DEBUG & DEBUG_MESSAGES)	printk("NOP");#endif	break;    case 1:	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);	msg = msgqueue_getmsg(&host->scsi.msgs, 0);	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2");	sbic_arm_write(host->scsi.io_port, SBIC_DATA, msg->msg[0]);	host->scsi.last_message = msg->msg[0];#if (DEBUG & DEBUG_MESSAGES)	scsi_print_msg(msg->msg);#endif	break;    default:	/*	 * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14)	 * 'When a target sends this (MESSAGE_REJECT) message, it	 *  shall change to MESSAGE IN phase and send this message	 *  prior to requesting additional message bytes from the	 *  initiator.  This provides an interlock so that the	 *  initiator can determine which message byte is rejected.	 */	sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0);	sbic_arm_writenext(host->scsi.io_port, 0);	sbic_arm_writenext(host->scsi.io_port, message_length);	acornscsi_sbic_issuecmd(host, CMND_XFERINFO);	msgnr = 0;	while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) {	    unsigned int i;#if (DEBUG & DEBUG_MESSAGES)	    scsi_print_msg(msg);#endif	    i = 0;	    if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000))		printk("scsi%d: timeout while sending message\n", host->host->host_no);	    host->scsi.last_message = msg->msg[0];	    if (msg->msg[0] == EXTENDED_MESSAGE)		host->scsi.last_message |= msg->msg[2] << 8;	    if (i != msg->length)		break;	}	break;    }#if (DEBUG & DEBUG_MESSAGES)    printk("\n");#endif}/* * Function: void acornscsi_readstatusbyte(AS_Host *host) * Purpose : Read status byte from connected target * Params  : host - host connected to target */staticvoid acornscsi_readstatusbyte(AS_Host *host){    acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT);    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte");    host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, SBIC_DATA);}/* * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host) * Purpose : Read one message byte from connected target * Params  : host - host connected to target */staticunsigned char acornscsi_readmessagebyte(AS_Host *host){    unsigned char message;    acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte");    message = sbic_arm_read(host->scsi.io_port, SBIC_DATA);    /* wait for MSGIN-XFER-PAUSED */    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte");    sbic_arm_read(host->scsi.io_port, SBIC_SSR);    return message;}/* * Function: void acornscsi_message(AS_Host *host) * Purpose : Read complete message from connected target & action message * Params  : host - host connected to target */staticvoid acornscsi_message(AS_Host *host){    unsigned char message[16];    unsigned int msgidx = 0, msglen = 1;    do {	message[msgidx] = acornscsi_readmessagebyte(host);	switch (msgidx) {	case 0:	    if (message[0] == EXTENDED_MESSAGE ||		(message[0] >= 0x20 && message[0] <= 0x2f))		msglen = 2;	    break;	case 1:	    if (message[0] == EXTENDED_MESSAGE)		msglen += message[msgidx];	    break;	}	msgidx += 1;	if (msgidx < msglen) {	    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);	    /* wait for next msg-in */	    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack");	    sbic_arm_read(host->scsi.io_port, SBIC_SSR);	}    } while (msgidx < msglen);#if (DEBUG & DEBUG_MESSAGES)    printk("scsi%d.%c: message in: ",	    host->host->host_no, acornscsi_target(host));    scsi_print_msg(message);    printk("\n");#endif    if (host->scsi.phase == PHASE_RECONNECTED) {	/*	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)	 * 'Whenever a target reconnects to an initiator to continue	 *  a tagged I/O process, the SIMPLE QUEUE TAG message shall	 *  be sent immediately following the IDENTIFY message...'	 */	if (message[0] == SIMPLE_QUEUE_TAG)	    host->scsi.reconnected.tag = message[1];	if (acornscsi_reconnect_finish(host))	    host->scsi.phase = PHASE_MSGIN;    }    switch (message[0]) {    case ABORT:    case ABORT_TAG:    case COMMAND_COMPLETE:	if (host->scsi.phase != PHASE_STATUSIN) {	    printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n",		    host->host->host_no, acornscsi_target(host));	    acornscsi_dumplog(host, host->SCpnt->device->id);	}	host->scsi.phase = PHASE_DONE;	host->scsi.SCp.Message = message[0];	break;    case SAVE_POINTERS:	/*	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20)	 * 'The SAVE DATA POINTER message is sent from a target to	 *  direct the initiator to copy the active data pointer to	 *  the saved data pointer for the current I/O process.	 */	acornscsi_dma_cleanup(host);	host->SCpnt->SCp = host->scsi.SCp;	host->SCpnt->SCp.sent_command = 0;	host->scsi.phase = PHASE_MSGIN;	break;    case RESTORE_POINTERS:	/*	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19)	 * 'The RESTORE POINTERS message is sent from a target to	 *  direct the initiator to copy the most recently saved	 *  command, data, and status pointers for the I/O process	 *  to the corresponding active pointers.  The command and	 *  status pointers shall be restored to the beginning of	 *  the present command and status areas.'	 */	acornscsi_dma_cleanup(host);	host->scsi.SCp = host->SCpnt->SCp;	host->scsi.phase = PHASE_MSGIN;	break;    case DISCONNECT:	/*	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2)	 * 'On those occasions when an error or exception condition occurs	 *  and the target elects to repeat the information transfer, the	 *  target may repeat the transfer either issuing a RESTORE POINTERS	 *  message or by disconnecting without issuing a SAVE POINTERS	 *  message.  When reconnection is completed, the most recent	 *  saved pointer values are restored.'	 */	acornscsi_dma_cleanup(host);	host->scsi.phase = PHASE_DISCONNECT;	break;    case MESSAGE_REJECT:#if 0 /* this isn't needed any more */	/*	 * If we were negociating sync transfer, we don't yet know if	 * this REJECT is for the sync transfer or for the tagged queue/wide	 * transfer.  Re-initiate sync transfer negociation now, and if	 * we got a REJECT in response to SDTR, then it'll be set to DONE.	 */	if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST)	    host->device[host->SCpnt->device->id].sync_state = SYNC_NEGOCIATE;#endif	/*	 * If we have any messages waiting to go out, then assert ATN now	 */	if (msgqueue_msglength(&host->scsi.msgs))	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);	switch (host->scsi.last_message) {#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE	case HEAD_OF_QUEUE_TAG:	case ORDERED_QUEUE_TAG:	case SIMPLE_QUEUE_TAG:	    /*	     * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)	     *  If a target does not implement tagged queuing and a queue tag	     *  message is received, it shall respond with a MESSAGE REJECT	     *  message and accept the I/O process as if it were untagged.	     */	    printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",		    host->host->host_no, acornscsi_target(host));	    host->SCpnt->device->simple_tags = 0;	    set_bit(host->SCpnt->device->id * 8 + host->SCpnt->device->lun, host->busyluns);	    break;#endif	case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8):	    /*	     * Target can't handle synchronous transfers	     */	    printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",		    host->host->host_no, acornscsi_target(host));	    host->device[host->SCpnt->device->id].sync_xfer = SYNCHTRANSFER_2DBA;	    host->device[host->SCpnt->device->id].sync_state = SYNC_ASYNCHRONOUS;	    sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);	    break;	default:	    break;	}	break;    case QUEUE_FULL:	/* TODO: target queue is full */	break;    case SIMPLE_QUEUE_TAG:	/* tag queue reconnect... message[1] = queue tag.  Print something to indicate something happened! */	printk("scsi%d.%c: reconnect queue tag %02X\n",		host->host->host_no, acornscsi_target(host),		message[1]);	break;    case EXTENDED_MESSAGE:	switch (message[2]) {#ifdef CONFIG_SCSI_ACORNSCSI_SYNC	case EXTENDED_SDTR:	    if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST) {		/*		 * We requested synchronous transfers.  This isn't quite right...		 * We can only say if this succeeded if we proceed on to execute the		 * command from this message.  If we get a MESSAGE PARITY ERROR,		 * and the target retries fail, then we fallback to asynchronous mode		 */		host->device[host->SCpnt->device->id].sync_state = SYNC_COMPLETED;		printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",			host->host->host_no, acornscsi_target(host),			message[4], message[3] * 4);		host->device[host->SCpnt->device->id].sync_xfer =			calc_sync_xfer(message[3] * 4, message[4]);	    } else {		unsigned char period, length;		/*		 * Target requested synchronous transfers.  The agreement is only		 * to be in operation AFTER the target leaves message out phase.		 */		acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);		period = max_t(unsigned int, message[3], sdtr_period / 4);		length = min_t(unsigned int, message[4], sdtr_size);		msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,				 EXTENDED_SDTR, period, length);		host->device[host->SCpnt->device->id].sync_xfer =			calc_sync_xfer(period * 4, length);	    }	    sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);	    break;#else	    /* We do not accept synchronous transfers.  Respond with a	     * MESSAGE_REJECT.	     */#endif	case EXTENDED_WDTR:	    /* The WD33C93A is only 8-bit.  We respond with a MESSAGE_REJECT	     * to a wide data transfer request.	     */	default:	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);	    msgqueue_flush(&host->scsi.msgs);	    msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);	    break;	}	break;#ifdef CONFIG_SCSI_ACORNSCSI_LINK    case LINKED_CMD_COMPLETE:    case LINKED_FLG_CMD_COMPLETE:	/*	 * We don't support linked commands yet	 */	if (0) {#if (DEBUG & DEBUG_LINK)	    printk("scsi%d.%c: lun %d tag %d linked command complete\n",		    host->host->host_no, acornscsi_target(host), host->SCpnt->tag);#endif	    /*	     * A linked command should only terminate with one of these messages	     * if there are more linked commands available.	     */	    if (!host->SCpnt->next_link) {		printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n",			instance->host_no, acornscsi_target(host), host->SCpnt->tag);		acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);		msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);	    } else {		Scsi_Cmnd *SCpnt = host->SCpnt;		acornscsi_dma_cleanup(host);		host->SCpnt = host->SCpnt->next_link;		host->SCpnt->tag = SCpnt->tag;		SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status;		SCpnt->done(SCpnt);		/* initialise host->SCpnt->SCp */	    }	    break;	}#endif    default: /* reject message */	printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",		host->host->host_no, acornscsi_target(host),		message[0]);	acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);	msgqueue_flush(&host->scsi.msgs);	msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);	host->scsi.phase = PHASE_MSGIN;	break;    }    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);}/* * Function: int acornscsi_buildmessages(AS_Host *host) * Purpose : build the connection messages for a host * Params  : host - host to add messages to */staticvoid acornscsi_buildmessages(AS_Host *host){#if 0    /* does the device need resetting? */    if (cmd_reset) {	msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET);	return;    }#endif    msgqueue_addmsg(&host->scsi.msgs, 1,		     IDENTIFY(host->device[host->SCpnt->device->id].disconnect_ok,			     host->SCpnt->device->lun));#if 0    /* does the device need the current command aborted */    if (cmd_aborted) {	acornscsi_abortcmd(host->SCpnt->tag);	return;    }#endif#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE    if (host->SCpnt->tag) {	unsigned int tag_type;	if (host->SCpnt->cmnd[0] == REQUEST_SENSE ||	    host->SCpnt->cmnd[0] == TEST_UNIT_READY ||	    host->SCpnt->cmnd[0] == INQUIRY)	    tag_type = HEAD_OF_QUEUE_TAG;	else	    tag_type = SIMPLE_QUEUE_TAG;	msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag);    }#endif#ifdef CONFIG_SCSI_ACORNSCSI_SYNC    if (host->device[host->SCpnt->device->id].sync_state == SYNC_NEGOCIATE) {	host->device[host->SCpnt->device->id].sync_state = SYNC_SENT_REQUEST;	msgqueue_addmsg(&host->scsi.msgs, 5,			 EXTENDED_MESSAGE, 3, EXTENDED_SDTR,			 sdtr_period / 4, sdtr_size);    }#endif}/* * Function: int acornscsi_starttransfer(AS_Host *host) * Purpose : transfer data to/from connected target * Params  : host - host to which target is connected * Returns : 0 if failure */staticint acornscsi_starttransfer(AS_Host *host){    int residual;    if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) {

⌨️ 快捷键说明

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