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

📄 acornscsi.c.2

📁 arm平台上的uclinux系统全部源代码
💻 2
📖 第 1 页 / 共 5 页
字号:
{    unsigned int prev;    do {	signed int statptr;	printk ("%c:", target == 8 ? 'H' : ('0' + target));	statptr = status_ptr[target] - 10;	if (statptr < 0)	    statptr += 16;	prev = status[target][statptr].when;	for (; statptr != status_ptr[target]; statptr = (statptr + 1) & 15) {	    if (status[target][statptr].when) {#ifdef CONFIG_ACORNSCSI_CONSTANTS		printk ("%c%02X:S=",			status[target][statptr].irq ? '-' : ' ',			status[target][statptr].ph);		print_scsi_status (status[target][statptr].ssr);#else		printk ("%c%02X:%02X",			status[target][statptr].irq ? '-' : ' ',			status[target][statptr].ph,			status[target][statptr].ssr);#endif		printk ("+%02ld",			(status[target][statptr].when - prev) < 100 ?				(status[target][statptr].when - prev) : 99);		prev = status[target][statptr].when;	    }	}	printk ("\n");	if (target == 8)	    break;	target = 8;    } while (1);}staticchar acornscsi_target (AS_Host *host){	if (host->SCpnt)		return '0' + host->SCpnt->target;	return 'H';}staticvoid acornscsi_dumpdma (AS_Host *host, char *where){	unsigned int mode, addr, len;	mode = dmac_read (host->dma.io_port, MODECON);	addr = dmac_address (host->dma.io_port);	len  = dmac_read (host->dma.io_port, TXCNTHI) << 8 |	       dmac_read (host->dma.io_port, TXCNTLO);	printk ("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",		host->host->host_no, where,		mode, addr, (len + 1) & 0xffff,		dmac_read (host->dma.io_port, MASKREG));	printk ("DMA @%06x, ", host->dma.start_addr);	printk ("BH @%p +%04x, ", host->scsi.SCp.ptr,		host->scsi.SCp.this_residual);	printk ("DT @+%04x ST @+%04x", host->dma.transferred,		host->scsi.SCp.have_data_in);	printk ("\n");}/* * Prototype: cmdtype_t acornscsi_cmdtype (int command) * Purpose  : differentiate READ from WRITE from other commands * Params   : command - command to interpret * Returns  : CMD_READ	- command reads data, *	      CMD_WRITE - command writes data, *	      CMD_MISC	- everything else */static inlinecmdtype_t acornscsi_cmdtype (int command){    switch (command) {    case WRITE_6:  case WRITE_10:  case WRITE_12:	return CMD_WRITE;    case READ_6:   case READ_10:   case READ_12:	return CMD_READ;    default:	return CMD_MISC;    }}/* * Prototype: int acornscsi_datadirection (int command) * Purpose  : differentiate between commands that have a DATA IN phase *	      and a DATA OUT phase * Params   : command - command to interpret * Returns  : DATADIR_OUT - data out phase expected *	      DATADIR_IN  - data in phase expected */staticdatadir_t acornscsi_datadirection (int command){    switch (command) {    case CHANGE_DEFINITION:	case COMPARE:		case COPY:    case COPY_VERIFY:		case LOG_SELECT:	case MODE_SELECT:    case MODE_SELECT_10:	case SEND_DIAGNOSTIC:	case WRITE_BUFFER:    case FORMAT_UNIT:		case REASSIGN_BLOCKS:	case RESERVE:    case SEARCH_EQUAL:		case SEARCH_HIGH:	case SEARCH_LOW:    case WRITE_6:		case WRITE_10:		case WRITE_VERIFY:    case UPDATE_BLOCK:		case WRITE_LONG:	case WRITE_SAME:    case SEARCH_HIGH_12:	case SEARCH_EQUAL_12:	case SEARCH_LOW_12:    case WRITE_12:		case WRITE_VERIFY_12:	case SET_WINDOW:    case MEDIUM_SCAN:		case SEND_VOLUME_TAG:	case 0xea:	return DATADIR_OUT;    default:	return DATADIR_IN;    }}/* * Purpose  : provide values for synchronous transfers with 33C93. * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting *	Modified by Russell King for 8MHz WD33C93A */static struct sync_xfer_tbl {    unsigned int period_ns;    unsigned char reg_value;} sync_xfer_table[] = {    {	1, 0x20 },    { 249, 0x20 },	{ 374, 0x30 },    { 499, 0x40 },    { 624, 0x50 },	{ 749, 0x60 },    { 874, 0x70 },    { 999, 0x00 },	{   0,	  0 }};/* * Prototype: int acornscsi_getperiod (unsigned char syncxfer) * Purpose  : period for the synchronous transfer setting * Params   : syncxfer SYNCXFER register value * Returns  : period in ns. */staticint acornscsi_getperiod (unsigned char syncxfer){    int i;    syncxfer &= 0xf0;    if (syncxfer == 0x10)	syncxfer = 0;    for (i = 1; sync_xfer_table[i].period_ns; i++)	if (syncxfer == sync_xfer_table[i].reg_value)	    return sync_xfer_table[i].period_ns;    return 0;}/* * Prototype: int round_period (unsigned int period) * Purpose  : return index into above table for a required REQ period * Params   : period - time (ns) for REQ * Returns  : table index * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting */static inlineint round_period (unsigned int period){    int i;    for (i = 1; sync_xfer_table[i].period_ns; i++) {	if ((period <= sync_xfer_table[i].period_ns) &&	    (period > sync_xfer_table[i - 1].period_ns))	    return i;    }    return 7;}/* * Prototype: unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) * Purpose  : calculate value for 33c93s SYNC register * Params   : period - time (ns) for REQ *	      offset - offset in bytes between REQ/ACK * Returns  : value for SYNC register * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting */staticunsigned char calc_sync_xfer (unsigned int period, unsigned int offset){    return sync_xfer_table[round_period(period)].reg_value |		((offset < SDTR_SIZE) ? offset : SDTR_SIZE);}/* ==================================================================================== * Command functions *//* * Function: acornscsi_kick (AS_Host *host) * Purpose : kick next command to interface * Params  : host - host to send command to * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING * Notes   : interrupts are always disabled! */staticintr_ret_t acornscsi_kick (AS_Host *host){    int from_queue = 0;    Scsi_Cmnd *SCpnt;    /* first check to see if a command is waiting to be executed */    SCpnt = host->origSCpnt;    host->origSCpnt = NULL;    /* retrieve next command */    if (!SCpnt) {	SCpnt = queue_remove_exclude (&host->queues.issue, host->busyluns);	if (!SCpnt)	    return INTR_IDLE;	from_queue = 1;    }    if (host->scsi.disconnectable && host->SCpnt) {	queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt);	host->scsi.disconnectable = 0;#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))	DBG(host->SCpnt, printk ("scsi%d.%c: moved command to disconnected queue\n",		host->host->host_no, acornscsi_target (host)));#endif	host->SCpnt = NULL;    }    /*     * If we have an interrupt pending, then we may have been reselected.     * In this case, we don't want to write to the registers     */    if (!(sbic_arm_read (host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {	sbic_arm_write (host->scsi.io_port, DESTID, SCpnt->target);	sbic_arm_write (host->scsi.io_port, CMND, CMND_SELWITHATN);    }    /*     * claim host busy - all of these must happen atomically wrt     * our interrupt routine.  Failure means command loss.     */    host->scsi.phase = PHASE_CONNECTING;    host->SCpnt = SCpnt;    host->scsi.SCp = SCpnt->SCp;    host->dma.xfer_setup = 0;    host->dma.xfer_required = 0;#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT))    DBG(SCpnt,printk ("scsi%d.%c: starting cmd %02X\n",	    host->host->host_no, '0' + SCpnt->target,	    SCpnt->cmnd[0]));#endif    if (from_queue) {#ifdef SCSI2_TAG	/*	 * tagged queueing - allocate a new tag to this command	 */	if (SCpnt->device->tagged_queue) {	    SCpnt->device->current_tag += 1;	    if (SCpnt->device->current_tag == 0)		SCpnt->device->current_tag = 1;	    SCpnt->tag = SCpnt->device->current_tag;	} else#endif	    set_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns);	host->stats.removes += 1;	switch (acornscsi_cmdtype (SCpnt->cmnd[0])) {	case CMD_WRITE:	    host->stats.writes += 1;	    break;	case CMD_READ:	    host->stats.reads += 1;	    break;	case CMD_MISC:	    host->stats.miscs += 1;	    break;	}    }    return INTR_PROCESSING;}    /* * Function: void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) * Purpose : complete processing for command * Params  : host   - interface that completed *	     result - driver byte of result */staticvoid acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result){    Scsi_Cmnd *SCpnt = *SCpntp;    /* clean up */    sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);    host->stats.fins += 1;    if (SCpnt) {	*SCpntp = NULL;	acornscsi_dma_cleanup (host);	SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status;	/*	 * In theory, this should not happen.  In practice, it seems to.	 * Only trigger an error if the device attempts to report all happy	 * but with untransferred buffers...  If we don't do something, then	 * data loss will occur.  Should we check SCpnt->underflow here?	 * It doesn't appear to be set to something meaningful by the higher	 * levels all the time.	 */	if (host->scsi.SCp.ptr && result == DID_OK &&		acornscsi_cmdtype (SCpnt->cmnd[0]) != CMD_MISC) {	    switch (status_byte (SCpnt->result)) {	    case CHECK_CONDITION:	    case COMMAND_TERMINATED:	    case BUSY:	    case QUEUE_FULL:	    case RESERVATION_CONFLICT:		break;	    default:		printk (KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",			host->host->host_no, SCpnt->result);		print_command (SCpnt->cmnd);		acornscsi_dumpdma (host, "done");	 	acornscsi_dumplog (host, SCpnt->target);		SCpnt->result &= 0xffff;		SCpnt->result |= DID_ERROR << 16;	    }	}	if (!SCpnt->scsi_done)	    panic ("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no);	clear_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns);	SCpnt->scsi_done (SCpnt);    } else	printk ("scsi%d: null command in acornscsi_done", host->host->host_no);    host->scsi.phase = PHASE_IDLE;}/* ==================================================================================== * DMA routines *//* * Purpose  : update SCSI Data Pointer * Notes    : this will only be one SG entry or less */staticvoid acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int length){    SCp->ptr += length;    SCp->this_residual -= length;    if (!SCp->this_residual) {	if (SCp->buffers_residual) {	    SCp->buffer++;	    SCp->buffers_residual--;	    SCp->ptr = (char *)SCp->buffer->address;	    SCp->this_residual = SCp->buffer->length;	} else	    SCp->ptr = NULL;    }}/* * Prototype: void acornscsi_data_read (AS_Host *host, char *ptr, *				unsigned int start_addr, unsigned int length) * Purpose  : read data from DMA RAM * Params   : host - host to transfer from *	      ptr  - DRAM address *	      start_addr - host mem address *	      length - number of bytes to transfer * Notes    : this will only be one SG entry or less */staticvoid acornscsi_data_read (AS_Host *host, char *ptr,				 unsigned int start_addr, unsigned int length){    extern void __acornscsi_in (int port, char *buf, int len);    unsigned int page, offset, len = length;    page = (start_addr >> 12);    offset = start_addr & ((1 << 12) - 1);    outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);    while (len > 0) {	unsigned int this_len;	if (len + offset > (1 << 12))	    this_len = (1 << 12) - offset;	else	    this_len = len;	__acornscsi_in (host->card.io_ram + (offset << 1), ptr, this_len);	offset += this_len;	ptr += this_len;	len -= this_len;	if (offset == (1 << 12)) {	    offset = 0;	    page ++;	    outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);	}    }    outb (host->card.page_reg, host->card.io_page);}/* * Prototype: void acornscsi_data_write (AS_Host *host, char *ptr, *				unsigned int start_addr, unsigned int length) * Purpose  : write data to DMA RAM * Params   : host - host to transfer from *	      ptr  - DRAM address *	      start_addr - host mem address *	      length - number of bytes to transfer * Notes    : this will only be one SG entry or less */staticvoid acornscsi_data_write (AS_Host *host, char *ptr,				 unsigned int start_addr, unsigned int length){    extern void __acornscsi_out (int port, char *buf, int len);    unsigned int page, offset, len = length;    page = (start_addr >> 12);    offset = start_addr & ((1 << 12) - 1);    outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);    while (len > 0) {	unsigned int this_len;

⌨️ 快捷键说明

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