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

📄 seagate.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
      for (j = 0; !base_address && j < NUM_SIGNATURES; ++j)        if (check_signature (seagate_bases[i] + signatures[j].offset,                             signatures[j].signature, signatures[j].length))        {          base_address = seagate_bases[i];          controller_type = signatures[j].type;        }#endif /* OVERRIDE */  }    /* (! controller_type) */  tpnt->this_id = (controller_type == SEAGATE) ? 7 : 6;  tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR;  if (!base_address) {    DANY ("ST0x / TMC-8xx not detected.\n");    return 0;  }  st0x_cr_sr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00);  st0x_dr = st0x_cr_sr + 0x200;  DANY ("%s detected. Base address = %x, cr = %x, dr = %x\n",	tpnt->name, base_address, st0x_cr_sr, st0x_dr);/* *    At all times, we will use IRQ 5.  Should also check for IRQ3 if we *      loose our first interrupt. */  instance = scsi_register (tpnt, 0);  hostno = instance->host_no;  if (request_irq (irq, do_seagate_reconnect_intr, SA_INTERRUPT,		   (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", NULL)) {    printk ("scsi%d : unable to allocate IRQ%d\n", hostno, irq);    return 0;  }  instance->irq = irq;  instance->io_port = base_address;#ifdef SLOW_RATE  printk( "Calibrating borken timer... " );  borken_init ();  printk( " %d cycles per transfer\n", borken_calibration );#endif  printk( "This is one second... " );  {    int clock;    ULOOP( 1*1000*1000 ) {      volatile int x = STATUS;      if (TIMEOUT) break;    }  }  printk ("done, %s options:"#ifdef ARBITRATE            " ARBITRATE"#endif#ifdef DEBUG            " DEBUG"#endif#ifdef FAST            " FAST"#ifdef FAST32            "32"#endif#endif#ifdef LINKED            " LINKED"#endif#ifdef PARITY            " PARITY"#endif#ifdef SEAGATE_USE_ASM            " SEAGATE_USE_ASM"#endif#ifdef SLOW_RATE            " SLOW_RATE"#endif#ifdef SWAPSTAT            " SWAPSTAT"#endif#ifdef SWAPCNTDATA            " SWAPCNTDATA"#endif	  "\n", tpnt->name);  return 1;}const char *seagate_st0x_info (struct Scsi_Host *shpnt){  static char buffer[64];  sprintf (buffer, "%s at irq %d, address 0x%05X",           (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR,           irq, base_address);  return buffer;}/* * These are our saved pointers for the outstanding command that is * waiting for a reconnect */static unsigned char current_target, current_lun;static unsigned char *current_cmnd, *current_data;static int current_nobuffs;static struct scatterlist *current_buffer;static int current_bufflen;#ifdef LINKED/* * linked_connected indicates whether or not we are currently connected to * linked_target, linked_lun and in an INFORMATION TRANSFER phase, * using linked commands. */static int linked_connected = 0;static unsigned char linked_target, linked_lun;#endifstatic void (*done_fn) (Scsi_Cmnd *) = NULL;static Scsi_Cmnd *SCint = NULL;/* * These control whether or not disconnect / reconnect will be attempted, * or are being attempted. */#define NO_RECONNECT    0#define RECONNECT_NOW   1#define CAN_RECONNECT   2/* * LINKED_RIGHT indicates that we are currently connected to the correct target * for this command, LINKED_WRONG indicates that we are connected to the wrong * target. Note that these imply CAN_RECONNECT and require defined(LINKED). */#define LINKED_RIGHT    3#define LINKED_WRONG    4/* * This determines if we are expecting to reconnect or not. */static int should_reconnect = 0;/* * The seagate_reconnect_intr routine is called when a target reselects the * host adapter.  This occurs on the interrupt triggered by the target * asserting SEL. */static void do_seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs){  unsigned long flags;  spin_lock_irqsave(&io_request_lock, flags);  seagate_reconnect_intr(irq, dev_id, regs);  spin_unlock_irqrestore(&io_request_lock, flags);}static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs){  int temp;  Scsi_Cmnd *SCtmp;  DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);  if (!should_reconnect)    printk ("scsi%d: unexpected interrupt.\n", hostno);  else  {    should_reconnect = 0;    DPRINTK (PHASE_RESELECT, "scsi%d : internal_command("            "%d, %08x, %08x, RECONNECT_NOW\n", hostno,            current_target, current_data, current_bufflen);    temp = internal_command (current_target, current_lun, current_cmnd,                             current_data, current_bufflen, RECONNECT_NOW);    if (msg_byte (temp) != DISCONNECT)    {      if (done_fn)      {        DPRINTK (PHASE_RESELECT, "scsi%d : done_fn(%d,%08x)", hostno,                hostno, temp);        if (!SCint)          panic ("SCint == NULL in seagate");        SCtmp = SCint;        SCint = NULL;        SCtmp->result = temp;        done_fn (SCtmp);      }      else        printk ("done_fn() not defined.\n");    }  }}/* * The seagate_st0x_queue_command() function provides a queued interface * to the seagate SCSI driver.  Basically, it just passes control onto the * seagate_command() function, after fixing it so that the done_fn() * is set to the one passed to the function.  We have to be very careful, * because there are some commands on some devices that do not disconnect, * and if we simply call the done_fn when the command is done then another * command is started and queue_command is called again...  We end up * overflowing the kernel stack, and this tends not to be such a good idea. */static int recursion_depth = 0;int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)){  int result, reconnect;  Scsi_Cmnd *SCtmp;  DANY( "seagate: que_command" );  done_fn = done;  current_target = SCpnt->target;  current_lun = SCpnt->lun;  (const void *) current_cmnd = SCpnt->cmnd;  current_data = (unsigned char *) SCpnt->request_buffer;  current_bufflen = SCpnt->request_bufflen;  SCint = SCpnt;  if (recursion_depth) return 0;  recursion_depth++;  do  {#ifdef LINKED/* * Set linked command bit in control field of SCSI command. */    current_cmnd[SCpnt->cmd_len] |= 0x01;    if (linked_connected)    {      DPRINTK (DEBUG_LINKED, 	       "scsi%d : using linked commands, current I_T_L nexus is ", hostno);      if ((linked_target == current_target) && (linked_lun == current_lun))      {        DPRINTK (DEBUG_LINKED, "correct\n");        reconnect = LINKED_RIGHT;      }      else      {        DPRINTK (DEBUG_LINKED, "incorrect\n");        reconnect = LINKED_WRONG;      }    }    else#endif /* LINKED */      reconnect = CAN_RECONNECT;    result = internal_command (SCint->target, SCint->lun, SCint->cmnd,                               SCint->request_buffer, SCint->request_bufflen, reconnect);    if (msg_byte (result) == DISCONNECT) break;    SCtmp = SCint;    SCint = NULL;    SCtmp->result = result;    done_fn (SCtmp);  }  while (SCint);  recursion_depth--;  return 0;}int seagate_st0x_command (Scsi_Cmnd * SCpnt){  return internal_command (SCpnt->target, SCpnt->lun, SCpnt->cmnd,                           SCpnt->request_buffer, SCpnt->request_bufflen,                           (int) NO_RECONNECT);}static int internal_command (unsigned char target, unsigned char lun,                              const void *cmnd, void *buff, int bufflen, int reselect){  unsigned char *data = NULL;  struct scatterlist *buffer = NULL;  int clock, temp, nobuffs = 0, done = 0, len = 0;  unsigned long flags;#ifdef DEBUG  int transfered = 0, phase = 0, newphase;#endif  register unsigned char status_read;  unsigned char tmp_data, tmp_control, status = 0, message = 0;  unsigned transfersize = 0, underflow = 0;#ifdef SLOW_RATE  int borken = (int) SCint->device->borken; /* Does the current target require					       Very Slow I/O ?  */#endif  incommand = 0;  st0x_aborted = 0;#if (DEBUG & PRINT_COMMAND)  printk ("scsi%d : target = %d, command = ", hostno, target);  print_command ((unsigned char *) cmnd);#endif#if (DEBUG & PHASE_RESELECT)  switch (reselect)  {    case RECONNECT_NOW:      printk ("scsi%d : reconnecting\n", hostno);      break;#ifdef LINKED    case LINKED_RIGHT:      printk ("scsi%d : connected, can reconnect\n", hostno);      break;    case LINKED_WRONG:      printk ("scsi%d : connected to wrong target, can reconnect\n", hostno);      break;#endif    case CAN_RECONNECT:      printk ("scsi%d : allowed to reconnect\n", hostno);      break;    default:      printk ("scsi%d : not allowed to reconnect\n", hostno);  }#endif  if (target == (controller_type == SEAGATE ? 7 : 6))    return DID_BAD_TARGET;/* *    We work it differently depending on if this is is "the first time," *      or a reconnect.  If this is a reselect phase, then SEL will *      be asserted, and we must skip selection / arbitration phases. */  switch (reselect)  {    case RECONNECT_NOW:      DPRINTK ( PHASE_RESELECT, "scsi%d : phase RESELECT \n", hostno);/* *    At this point, we should find the logical or of our ID and the original *      target's ID on the BUS, with BSY, SEL, and I/O signals asserted. * *      After ARBITRATION phase is completed, only SEL, BSY, and the *      target ID are asserted.  A valid initiator ID is not on the bus *      until IO is asserted, so we must wait for that. */      ULOOP( 100*1000 ) {        temp = STATUS;        if ((temp & STAT_IO) && !(temp & STAT_BSY))          break;        if (TIMEOUT) {          DPRINTK (PHASE_RESELECT, 		   "scsi%d : RESELECT timed out while waiting for IO .\n", hostno);          return (DID_BAD_INTR << 16);        }      }/* *    After I/O is asserted by the target, we can read our ID and its *      ID off of the BUS. */      if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40)))      {        DPRINTK (PHASE_RESELECT,		 "scsi%d : detected reconnect request to different target.\n"		 "\tData bus = %d\n", hostno, temp);        return (DID_BAD_INTR << 16);      }      if (!(temp & (1 << current_target)))      {        printk ("scsi%d : Unexpected reselect interrupt.  Data bus = %d\n",                hostno, temp);        return (DID_BAD_INTR << 16);      }      buffer = current_buffer;      cmnd = current_cmnd;              /* WDE add */      data = current_data;              /* WDE add */      len = current_bufflen;            /* WDE add */      nobuffs = current_nobuffs;/* *    We have determined that we have been selected.  At this point, *      we must respond to the reselection by asserting BSY ourselves */#if 1      WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);#else      WRITE_CONTROL (BASE_CMD | CMD_BSY);#endif/* *    The target will drop SEL, and raise BSY, at which time we must drop *      BSY. */      ULOOP( 100*1000 ) {	if (!(STATUS & STAT_SEL)) break;	if (TIMEOUT) {	  WRITE_CONTROL (BASE_CMD | CMD_INTR);	  DPRINTK (PHASE_RESELECT,		   "scsi%d : RESELECT timed out while waiting for SEL.\n", hostno);	  return (DID_BAD_INTR << 16);	}      }      WRITE_CONTROL (BASE_CMD);/* *    At this point, we have connected with the target and can get *      on with our lives. */      break;    case CAN_RECONNECT:#ifdef LINKED/* * This is a bletcherous hack, just as bad as the Unix #! interpreter stuff. * If it turns out we are using the wrong I_T_L nexus, the easiest way to deal * with it is to go into our INFORMATION TRANSFER PHASE code, send a ABORT * message on MESSAGE OUT phase, and then loop back to here. */    connect_loop:#endif      DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n", hostno);/* *    BUS FREE PHASE * *      On entry, we make sure that the BUS is in a BUS FREE *      phase, by insuring that both BSY and SEL are low for *      at least one bus settle delay.  Several reads help *      eliminate wire glitch. */#ifndef ARBITRATE#error FIXME: this is broken: we may not use jiffies here - we are under cli(). It will hardlock.      clock = jiffies + ST0X_BUS_FREE_DELAY;      while (((STATUS | STATUS | STATUS) &              (STAT_BSY | STAT_SEL)) &&             (!st0x_aborted) && time_before(jiffies, clock));      if (time_after(jiffies, clock))        return retcode (DID_BUS_BUSY);      else if (st0x_aborted)

⌨️ 快捷键说明

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