📄 seagate.c
字号:
#endif/* * We loop as long as we are in a data in phase, there is room to read, * and BSY is still active *//* SJT: Start. */#ifdef SEAGATE_USE_ASM/* * We loop as long as we are in a data in phase, there is room to read, * and BSY is still active */ /* Local variables : ecx = len, edi = data esi = st0x_cr_sr, ebx = st0x_dr */ __asm__ ( /* Test for room to read */ "orl %%ecx, %%ecx\n\t" "jz 2f\n\t" "cld\n\t"/* "movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%esi\n\t" *//* "movl " SYMBOL_NAME_STR(st0x_dr) ", %%ebx\n\t" */ "1:\t" "movb (%%esi), %%al\n\t" /* Test for BSY */ "test $1, %%al\n\t" "jz 2f\n\t" /* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, = STAT_IO, which is 4. */ "movb $0xe, %%ah\n\t" "andb %%al, %%ah\n\t" "cmpb $0x04, %%ah\n\t" "jne 2f\n\t" /* Test for REQ */ "test $0x10, %%al\n\t" "jz 1b\n\t" "movb (%%ebx), %%al\n\t" "stosb\n\t" "loop 1b\n\t" "2:\n"/* output */ : "=D" (data), "=c" (len) /* input */ : "0" (data), "1" (len), "S" (phys_to_virt(st0x_cr_sr)), "b" (phys_to_virt(st0x_dr)) /* clobbered */ : "eax","ebx", "esi"); #else /* SEAGATE_USE_ASM */ while (len) { unsigned char stat; stat = STATUS; if (!(stat & STAT_BSY) || ((stat & REQ_MASK) != REQ_DATAIN)) break; if (stat & STAT_REQ) { *data++ = DATA; --len; } }#endif /* SEAGATE_USE_ASM *//* SJT: End. */#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; DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data); } break; case REQ_CMDOUT: while (((status_read = STATUS) & STAT_BSY) && ((status_read & REQ_MASK) == REQ_CMDOUT)) if (status_read & STAT_REQ) { WRITE_DATA (*(const unsigned char *) cmnd); cmnd = 1 + (const unsigned char *) cmnd;#ifdef SLOW_RATE 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. */ WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE);/* * If we are reconnecting, then we must send an IDENTIFY message in * response to MSGOUT. */ switch (reselect) { case CAN_RECONNECT: WRITE_DATA (IDENTIFY (1, lun)); DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno); break;#ifdef LINKED case LINKED_WRONG: WRITE_DATA (ABORT); linked_connected = 0; reselect = CAN_RECONNECT; goto connect_loop; DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);#endif /* LINKED */ DPRINTK (DEBUG_LINKED, "correct\n"); default: WRITE_DATA (NOP); printk ("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target); } break; case REQ_MSGIN: switch (message = DATA) { case DISCONNECT: DANY ("seagate: deciding to disconnect\n"); 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; DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno); break;#ifdef LINKED case LINKED_CMD_COMPLETE: case LINKED_FLG_CMD_COMPLETE:#endif case COMMAND_COMPLETE:/* * Note : we should check for underflow here. */ DPRINTK (PHASE_MSGIN, "scsi%d : command complete.\n", hostno); done = 1; break; case ABORT: DPRINTK (PHASE_MSGIN, "scsi%d : abort message.\n", hostno); done = 1; break; case SAVE_POINTERS: current_buffer = buffer; current_bufflen = len; /* WDE add */ current_data = data; /* WDE mod */ current_nobuffs = nobuffs; DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno); break; case RESTORE_POINTERS: buffer = current_buffer; cmnd = current_cmnd; data = current_data; /* WDE mod */ len = current_bufflen; nobuffs = current_nobuffs; DPRINTK (PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno); break; default:/* * IDENTIFY distinguishes itself from the other messages by setting the * high byte. [FIXME: should not this read "the high bit"? - pavel@ucw.cz] * * 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) { DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7); } 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. */ DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target); } } break; default: printk ("scsi%d : unknown phase.\n", hostno); st0x_aborted = DID_ERROR; } /* end of switch (status_read & REQ_MASK) */#ifdef SLOW_RATE/* * 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(status_read & STAT_REQ) ends */ } /* while(((status_read = STATUS)...) ends */ DPRINTK (PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered);#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 LINKED else {/* * 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; DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established" "for linked command.\n", hostno); /* We also will need to adjust status to accommodate 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: DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno); linked_connected = 0; } }#endif /* LINKED */ if (should_reconnect) { DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command()" "with reconnect enabled.\n", hostno); WRITE_CONTROL (BASE_CMD | CMD_INTR); } else WRITE_CONTROL (BASE_CMD); return retcode (st0x_aborted);} /* end of internal_command */int seagate_st0x_abort (Scsi_Cmnd * SCpnt){ st0x_aborted = DID_ABORT; return SCSI_ABORT_PENDING;}#undef ULOOP#undef TIMEOUT/* * the seagate_st0x_reset function resets the SCSI bus */int seagate_st0x_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags){/* No timeouts - this command is going to fail because it was reset. */ DANY ("scsi%d: Reseting bus... ", hostno );/* assert RESET signal on SCSI bus. */ WRITE_CONTROL (BASE_CMD | CMD_RST); udelay( 20*1000 ); WRITE_CONTROL (BASE_CMD); st0x_aborted = DID_RESET; DANY ("done.\n"); return SCSI_RESET_WAKEUP;}int seagate_st0x_biosparam (Disk * disk, kdev_t dev, int *ip){ unsigned char buf[256 + sizeof (Scsi_Ioctl_Command)], cmd[6], *data, *page; Scsi_Ioctl_Command *sic = (Scsi_Ioctl_Command *) buf; int result, formatted_sectors, total_sectors; int cylinders, heads, sectors; int capacity;/* * Only SCSI-I CCS drives and later implement the necessary mode sense * pages. */ if (disk->device->scsi_level < 2) return -1; data = sic->data; cmd[0] = MODE_SENSE; cmd[1] = (disk->device->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 transferring 0 bytes in the out direction, and expect to get back * 24 bytes for each mode page. */ sic->inlen = 0; sic->outlen = 256; memcpy (data, cmd, 6); if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, sic))) {/* * 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->device, SCSI_IOCTL_SEND_COMMAND, sic))) { 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 compatible. The maximum BIOS geometry is 1024 cylinders * * 256 heads * 64 sectors. */ if ((cylinders > 1024) || (sectors > 64)) { /* The Seagate's seem to have some mapping. Multiply heads*sectors*cyl to get capacity. Then start rounding down. */ capacity = heads * sectors * cylinders; /* Old MFM Drives use this, so does the Seagate */ sectors = 17; heads = 2; capacity = capacity / sectors; while (cylinders > 1024) { heads *= 2; /* For some reason, they go in multiples */ cylinders = capacity / heads; } } 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;}#ifdef MODULE/* Eventually this will go into an include file, but this will be later */Scsi_Host_Template driver_template = SEAGATE_ST0X;#include "scsi_module.c"#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -