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

📄 acornscsi.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
    "reset - advanced mode",	/* 01 */    /* 2 */    "sel",			/* 11 */    "sel+xfer", 		/* 16 */    "data-out", 		/* 18 */    "data-in",			/* 19 */    "cmd",			/* 1A */    "stat",			/* 1B */    "??-out",			/* 1C */    "??-in",			/* 1D */    "msg-out",			/* 1E */    "msg-in",			/* 1F */    /* 12 */    "/ACK asserted",		/* 20 */    "save-data-ptr",		/* 21 */    "{re}sel",			/* 22 */    /* 15 */    "inv cmd",			/* 40 */    "unexpected disconnect",	/* 41 */    "sel timeout",		/* 42 */    "P err",			/* 43 */    "P err+ATN",		/* 44 */    "bad status byte",		/* 47 */    /* 21 */    "resel, no id",		/* 80 */    "resel",			/* 81 */    "discon",			/* 85 */};staticvoid print_scsi_status(unsigned int ssr){    if (acornscsi_map[ssr] != -1)	printk("%s:%s",		acornscsi_interrupttype[(ssr >> 4)],		acornscsi_interruptcode[acornscsi_map[ssr]]);    else	printk("%X:%X", ssr >> 4, ssr & 0x0f);    }    #endifstaticvoid print_sbic_status(int asr, int ssr, int cmdphase){#ifdef CONFIG_ACORNSCSI_CONSTANTS    printk("sbic: %c%c%c%c%c%c ",	    asr & ASR_INT ? 'I' : 'i',	    asr & ASR_LCI ? 'L' : 'l',	    asr & ASR_BSY ? 'B' : 'b',	    asr & ASR_CIP ? 'C' : 'c',	    asr & ASR_PE  ? 'P' : 'p',	    asr & ASR_DBR ? 'D' : 'd');    printk("scsi: ");    print_scsi_status(ssr);    printk(" ph %02X\n", cmdphase);#else    printk("sbic: %02X scsi: %X:%X ph: %02X\n",	    asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);#endif}static voidacornscsi_dumplogline(AS_Host *host, int target, int line){	unsigned long prev;	signed int ptr;	ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT;	if (ptr < 0)		ptr += STATUS_BUFFER_SIZE;	printk("%c: %3s:", target == 8 ? 'H' : '0' + target,		line == 0 ? "ph" : line == 1 ? "ssr" : "int");	prev = host->status[target][ptr].when;	for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) {		unsigned long time_diff;		if (!host->status[target][ptr].when)			continue;		switch (line) {		case 0:			printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ',					 host->status[target][ptr].ph);			break;		case 1:			printk(" %02X", host->status[target][ptr].ssr);			break;		case 2:			time_diff = host->status[target][ptr].when - prev;			prev = host->status[target][ptr].when;			if (time_diff == 0)				printk("==^");			else if (time_diff >= 100)				printk("   ");			else				printk(" %02ld", time_diff);			break;		}	}	printk("\n");}staticvoid acornscsi_dumplog(AS_Host *host, int target){    do {	acornscsi_dumplogline(host, target, 0);	acornscsi_dumplogline(host, target, 1);	acornscsi_dumplogline(host, target, 2);	if (target == 8)	    break;	target = 8;    } while (1);}staticchar acornscsi_target(AS_Host *host){	if (host->SCpnt)		return '0' + host->SCpnt->device->id;	return 'H';}/* * 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, SBIC_ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {	sbic_arm_write(host->scsi.io_port, SBIC_DESTID, SCpnt->device->id);	sbic_arm_write(host->scsi.io_port, SBIC_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;    host->dma.xfer_done = 0;#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT))    DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n",	    host->host->host_no, '0' + SCpnt->device->id,	    SCpnt->cmnd[0]));#endif    if (from_queue) {#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE	/*	 * tagged queueing - allocate a new tag to this command	 */	if (SCpnt->device->simple_tags) {	    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->device->id * 8 + SCpnt->device->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, SBIC_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 (result == DID_OK) {		int xfer_warn = 0;		if (SCpnt->underflow == 0) {			if (host->scsi.SCp.ptr &&			    acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC)				xfer_warn = 1;		} else {			if (host->scsi.SCp.scsi_xferred < SCpnt->underflow ||			    host->scsi.SCp.scsi_xferred != host->dma.transferred)				xfer_warn = 1;		}		/* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6)		 *  Targets which break data transfers into multiple		 *  connections shall end each successful connection		 *  (except possibly the last) with a SAVE DATA		 *  POINTER - DISCONNECT message sequence.		 *		 * This makes it difficult to ensure that a transfer has		 * completed.  If we reach the end of a transfer during		 * the command, then we can only have finished the transfer.		 * therefore, if we seem to have some data remaining, this		 * is not a problem.		 */		if (host->dma.xfer_done)			xfer_warn = 0;		if (xfer_warn) {		    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);			__scsi_print_command(SCpnt->cmnd);			acornscsi_dumpdma(host, "done");		 	acornscsi_dumplog(host, SCpnt->device->id);			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->device->id * 8 + SCpnt->device->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 *//*

⌨️ 快捷键说明

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