?? seagate.c
字號:
++buffer; len = buffer->length; data = (unsigned char *) buffer->address;#if (DEBUG & DEBUG_SG) printk("scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);#endif } break; case REQ_DATAIN : #ifdef SLOW_HANDSHAKE if (borken) {#if (DEBUG & (PHASE_DATAIN)) transfered += len;#endif for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) { *data++ = DATA; borken_wait();}#if (DEBUG & (PHASE_DATAIN)) transfered -= len;#endif } else#endif#ifdef FASTif (fast && transfersize && !(len % transfersize) && (len >= transfersize)#ifdef FAST32 && !(transfersize % 4)#endif ) {#if (DEBUG & DEBUG_FAST) printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" " len = %d, data = %08x\n", hostno, SCint->underflow, SCint->transfersize, len, data);#endif __asm__(" cld;"#ifdef FAST32" shr $2, %%ecx;1: movl (%%esi), %%eax; stosl;"#else"1: movb (%%esi), %%al; stosb;"#endif" loop 1b;" : : /* input */ "S" (st0x_dr), "D" (data), "c" (SCint->transfersize) : /* clobbered */ "eax", "ecx", "edi"); len -= transfersize; data += transfersize;#if (DEBUG & PHASE_DATAIN) printk("scsi%d: transfered += %d\n", hostno, transfersize); transfered += transfersize;#endif#if (DEBUG & DEBUG_FAST) printk("scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);#endif} else#endif{#if (DEBUG & PHASE_DATAIN) printk("scsi%d: transfered += %d\n", hostno, len); transfered += len; /* Assume we'll transfer it all, then subtract what we *didn't* transfer */#endif /* * We loop as long as we are in a data in phase, there is room to read, * and BSY is still active */ __asm__ (/* Local variables : ecx = len edi = data esi = st0x_cr_sr ebx = st0x_dr Test for room to read*/ "\torl %%ecx, %%ecx jz 2f cld movl _st0x_cr_sr, %%esi movl _st0x_dr, %%ebx1: movb (%%esi), %%al\n"/* Test for BSY*/ "\ttest $1, %%al jz 2f\n"/* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, = STAT_IO, which is 4.*/ "\tmovb $0xe, %%ah andb %%al, %%ah cmpb $0x04, %%ah jne 2f\n" /* Test for REQ*/ "\ttest $0x10, %%al jz 1b movb (%%ebx), %%al stosb loop 1b\n""2:\n" :/* output */"=D" (data), "=c" (len) :/* input */"0" (data), "1" (len) :/* clobbered */"eax","ebx", "esi"); #if (DEBUG & PHASE_DATAIN) printk("scsi%d: transfered -= %d\n", hostno, len); transfered -= len; /* Since we assumed all of Len got * transfered, correct our mistake */#endif} if (!len && nobuffs) { --nobuffs; ++buffer; len = buffer->length; data = (unsigned char *) buffer->address;#if (DEBUG & DEBUG_SG) printk("scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);#endif } break; case REQ_CMDOUT : while (((status_read = STATUS) & STAT_BSY) && ((status_read & REQ_MASK) == REQ_CMDOUT)) if (status_read & STAT_REQ) { DATA = *(unsigned char *) cmnd; cmnd = 1+(unsigned char *) cmnd;#ifdef SLOW_HANDSHAKE if (borken) borken_wait();#endif } break; case REQ_STATIN : status = DATA; break; case REQ_MSGOUT : /* * We can only have sent a MSG OUT if we requested to do this * by raising ATTN. So, we must drop ATTN. */ CONTROL = BASE_CMD | CMD_DRVR_ENABLE;/* * If we are reconecting, then we must send an IDENTIFY message in * response to MSGOUT. */ switch (reselect) { case CAN_RECONNECT: DATA = IDENTIFY(1, lun);#if (DEBUG & (PHASE_RESELECT | PHASE_MSGOUT)) printk("scsi%d : sent IDENTIFY message.\n", hostno);#endif break;#ifdef LINKED case LINKED_WRONG: DATA = ABORT; linked_connected = 0; reselect = CAN_RECONNECT; goto connect_loop;#if (DEBUG & (PHASE_MSGOUT | DEBUG_LINKED)) printk("scsi%d : sent ABORT message to cancle incorrect I_T_L nexus.\n", hostno);#endif#endif /* LINKED */#if (DEBUG & DEBUG_LINKED) printk("correct\n");#endif default: DATA = NOP; printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target); } break; case REQ_MSGIN : switch (message = DATA) { case DISCONNECT : should_reconnect = 1; current_data = data; /* WDE add */ current_buffer = buffer; current_bufflen = len; /* WDE add */ current_nobuffs = nobuffs;#ifdef LINKED linked_connected = 0;#endif done=1;#if (DEBUG & (PHASE_RESELECT | PHASE_MSGIN)) printk("scsi%d : disconnected.\n", hostno);#endif break;#ifdef LINKED case LINKED_CMD_COMPLETE: case LINKED_FLG_CMD_COMPLETE:#endif case COMMAND_COMPLETE :/* * Note : we should check for underflow here. */#if (DEBUG & PHASE_MSGIN) printk("scsi%d : command complete.\n", hostno);#endif done = 1; break; case ABORT :#if (DEBUG & PHASE_MSGIN) printk("scsi%d : abort message.\n", hostno);#endif done=1; break; case SAVE_POINTERS : current_buffer = buffer; current_bufflen = len; /* WDE add */ current_data = data; /* WDE mod */ current_nobuffs = nobuffs;#if (DEBUG & PHASE_MSGIN) printk("scsi%d : pointers saved.\n", hostno);#endif break; case RESTORE_POINTERS: buffer=current_buffer; cmnd=current_cmnd; data=current_data; /* WDE mod */ len=current_bufflen; nobuffs=current_nobuffs;#if (DEBUG & PHASE_MSGIN) printk("scsi%d : pointers restored.\n", hostno);#endif break; default:/* * IDENTIFY distinguishes itself from the other messages by setting the * high byte. * * Note : we need to handle at least one outstanding command per LUN, * and need to hash the SCSI command for that I_T_L nexus based on the * known ID (at this point) and LUN. */ if (message & 0x80) {#if (DEBUG & PHASE_MSGIN) printk("scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7);#endif } else {/* * We should go into a MESSAGE OUT phase, and send a MESSAGE_REJECT * if we run into a message that we don't like. The seagate driver * needs some serious restructuring first though. */#if (DEBUG & PHASE_MSGIN) printk("scsi%d : unknown message %d from target %d.\n", hostno, message, target);#endif } } break; default : printk("scsi%d : unknown phase.\n", hostno); st0x_aborted = DID_ERROR; } #ifdef SLOW_HANDSHAKE/* * I really don't care to deal with borken devices in each single * byte transfer case (ie, message in, message out, status), so * I'll do the wait here if necessary. */ if (borken) borken_wait();#endif } /* if ends */ } /* while ends */#if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT)) printk("scsi%d : Transfered %d bytes\n", hostno, transfered);#endif#if (DEBUG & PHASE_EXIT)#if 0 /* Doesn't work for scatter / gather */ printk("Buffer : \n"); for (i = 0; i < 20; ++i) printk ("%02x ", ((unsigned char *) data)[i]); /* WDE mod */ printk("\n");#endif printk("scsi%d : status = ", hostno); print_status(status); printk("message = %02x\n", message);#endif/* We shouldn't reach this until *after* BSY has been deasserted */#ifdef notyet if (st0x_aborted) { if (STATUS & STAT_BSY) { seagate_st0x_reset(NULL); st0x_aborted = DID_RESET; } abort_confirm = 1; } #endif#ifdef LINKEDelse {/* * Fix the message byte so that unsuspecting high level drivers don't * puke when they see a LINKED COMMAND message in place of the COMMAND * COMPLETE they may be expecting. Shouldn't be necessary, but it's * better to be on the safe side. * * A non LINKED* message byte will indicate that the command completed, * and we are now disconnected. */ switch (message) { case LINKED_CMD_COMPLETE : case LINKED_FLG_CMD_COMPLETE : message = COMMAND_COMPLETE; linked_target = current_target; linked_lun = current_lun; linked_connected = 1;#if (DEBUG & DEBUG_LINKED) printk("scsi%d : keeping I_T_L nexus established for linked command.\n", hostno);#endif/* * We also will need to adjust status to accomodate intermediate conditions. */ if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD)) status = GOOD; break;/* * We should also handle what are "normal" termination messages * here (ABORT, BUS_DEVICE_RESET?, and COMMAND_COMPLETE individually, * and flake if things aren't right. */ default :#if (DEBUG & DEBUG_LINKED) printk("scsi%d : closing I_T_L nexus.\n", hostno);#endif linked_connected = 0; } }#endif /* LINKED */ if (should_reconnect) {#if (DEBUG & PHASE_RESELECT) printk("scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno);#endif CONTROL = BASE_CMD | CMD_INTR ; } else CONTROL = BASE_CMD; return retcode (st0x_aborted); }int seagate_st0x_abort (Scsi_Cmnd * SCpnt, int code) { if (code) st0x_aborted = code; else st0x_aborted = DID_ABORT; return 0; }/* the seagate_st0x_reset function resets the SCSI bus*/ int seagate_st0x_reset (Scsi_Cmnd * SCpnt) { unsigned clock; /* No timeouts - this command is going to fail because it was reset. */#ifdef DEBUG printk("In seagate_st0x_reset()\n");#endif /* assert RESET signal on SCSI bus. */ CONTROL = BASE_CMD | CMD_RST; clock=jiffies+2; /* Wait. */ while (jiffies < clock); CONTROL = BASE_CMD; st0x_aborted = DID_RESET;#ifdef DEBUG printk("SCSI bus reset.\n");#endif if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; return 0; }#ifdef CONFIG_BLK_DEV_SD#include <asm/segment.h>#include "sd.h"#include "scsi_ioctl.h"int seagate_st0x_biosparam(int size, int dev, int* ip) { unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page; int *sizes, result, formatted_sectors, total_sectors; int cylinders, heads, sectors; Scsi_Device *disk; disk = rscsi_disks[MINOR(dev) >> 4].device;/* * Only SCSI-I CCS drives and later implement the necessary mode sense * pages. */ if (disk->scsi_level < 2) return -1; sizes = (int *) buf; data = (unsigned char *) (sizes + 2); cmd[0] = MODE_SENSE; cmd[1] = (disk->lun << 5) & 0xe5; cmd[2] = 0x04; /* Read page 4, rigid disk geometry page current values */ cmd[3] = 0; cmd[4] = 255; cmd[5] = 0;/* * We are transfering 0 bytes in the out direction, and expect to get back * 24 bytes for each mode page. */ sizes[0] = 0; sizes[1] = 256; memcpy (data, cmd, 6); if (!(result = kernel_scsi_ioctl (disk, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) {/* * The mode page lies beyond the MODE SENSE header, with length 4, and * the BLOCK DESCRIPTOR, with length header[3]. */ page = data + 4 + data[3]; heads = (int) page[5]; cylinders = (page[2] << 16) | (page[3] << 8) | page[4]; cmd[2] = 0x03; /* Read page 3, format page current values */ memcpy (data, cmd, 6); if (!(result = kernel_scsi_ioctl (disk, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) { page = data + 4 + data[3]; sectors = (page[10] << 8) | page[11]; /* * Get the total number of formatted sectors from the block descriptor, * so we can tell how many are being used for alternates. */ formatted_sectors = (data[4 + 1] << 16) | (data[4 + 2] << 8) | data[4 + 3] ; total_sectors = (heads * cylinders * sectors);/* * Adjust the real geometry by subtracting * (spare sectors / (heads * tracks)) cylinders from the number of cylinders. * * It appears that the CE cylinder CAN be a partial cylinder. */ printk("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %d\n", hostno, heads, cylinders, sectors, total_sectors, formatted_sectors); if (!heads || !sectors || !cylinders) result = -1; else cylinders -= ((total_sectors - formatted_sectors) / (heads * sectors));/* * Now, we need to do a sanity check on the geometry to see if it is * BIOS compatable. The maximum BIOS geometry is 1024 cylinders * * 256 heads * 64 sectors. */ if ((cylinders > 1024) || (sectors > 64)) result = -1; else { ip[0] = heads; ip[1] = sectors; ip[2] = cylinders; }/* * There should be an alternate mapping for things the seagate doesn't * understand, but I couldn't say what it is with reasonable certainty. */ } } return result;}#endif /* CONFIG_BLK_DEV_SD */#endif /* defined(CONFIG_SCSI_SEGATE) */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -