Enscript Output

extractedLnx/linux/drivers/scsi/seagate.c_internal_command.c

static int internal_command (unsigned char target, unsigned char lun, 
                             const void *cmnd, void *buff, int bufflen, 
                             int reselect)
{
  int len = 0;
  unsigned char *data = NULL;
  struct scatterlist *buffer = NULL;
  int nobuffs = 0;
  int clock;
  int temp;

#ifdef SLOW_HANDSHAKE
  int borken;                           /* Does the current target require
                                           Very Slow I/O ?  */
#endif

#if (DEBUG & PHASE_DATAIN) || (DEBUG & PHASE_DATOUT)
  int transfered = 0;

#endif

#if (((DEBUG & PHASE_ETC) == PHASE_ETC) || (DEBUG & PRINT_COMMAND) || \
     (DEBUG & PHASE_EXIT))
  int i;

#endif

#if ((DEBUG & PHASE_ETC) == PHASE_ETC)
  int phase = 0, newphase;

#endif

  int done = 0;
  unsigned char status = 0;
  unsigned char message = 0;
  register unsigned char status_read;

#ifndef OLDCNTDATASCEME
  volatile unsigned char tmp_data;
  volatile unsigned char tmp_control;
#endif
  unsigned transfersize = 0, underflow = 0;

  incommand = 0;
  st0x_aborted = 0;

#ifdef SLOW_HANDSHAKE
  borken = (int) SCint->device->borken;
#endif

#if (DEBUG & PRINT_COMMAND)
  printk ("scsi%d : target = %d, command = ", hostno, target);
  print_command ((unsigned char *) cmnd);
  printk ("\n");
#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:
#if (DEBUG & PHASE_RESELECT)
      printk ("scsi%d : phase RESELECT \n", hostno);
#endif

/*
 *    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.
 */
      clock = jiffies + 10;
      for (;;)
      {
        temp = STATUS;
        if ((temp & STAT_IO) && !(temp & STAT_BSY))
          break;

        if (jiffies > clock)
        {
#if (DEBUG & PHASE_RESELECT)
          printk ("scsi%d : RESELECT timed out while waiting for IO .\n",
                  hostno);
#endif
          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)))
      {
#if (DEBUG & PHASE_RESELECT)
        printk ("scsi%d : detected reconnect request to different target.\n"
                "\tData bus = %d\n", hostno, temp);
#endif
        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.
 */

      for (clock = jiffies + 10; (jiffies < clock) && (STATUS & STAT_SEL);) ;

      if (jiffies >= clock)
      {
        WRITE_CONTROL (BASE_CMD | CMD_INTR);
#if (DEBUG & PHASE_RESELECT)
        printk ("scsi%d : RESELECT timed out while waiting for SEL.\n", 
                hostno);
#endif
        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

#if (DEBUG & PHASE_BUS_FREE)
      printk ("scsi%d : phase = BUS FREE \n", hostno);
#endif

/*
 *    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.
 */

      clock = jiffies + ST0X_BUS_FREE_DELAY;

#if !defined (ARBITRATE)
      while (((STATUS | STATUS | STATUS) &
              (STAT_BSY | STAT_SEL)) &&
             (!st0x_aborted) && (jiffies < clock)) ;

      if (jiffies > clock)
        return retcode (DID_BUS_BUSY);
      else if (st0x_aborted)
        return retcode (st0x_aborted);
#endif

#if (DEBUG & PHASE_SELECTION)
      printk ("scsi%d : phase = SELECTION\n", hostno);
#endif

      clock = jiffies + ST0X_SELECTION_DELAY;

/*
 * Arbitration/selection procedure :
 * 1.  Disable drivers
 * 2.  Write HOST adapter address bit
 * 3.  Set start arbitration.
 * 4.  We get either ARBITRATION COMPLETE or SELECT at this
 *     point.
 * 5.  OR our ID and targets on bus.
 * 6.  Enable SCSI drivers and asserted SEL and ATTN
 */

#if defined(ARBITRATE)
      cli ();
      WRITE_CONTROL (0);
      WRITE_DATA ((controller_type == SEAGATE) ? 0x80 : 0x40);
      WRITE_CONTROL (CMD_START_ARB);
      sti ();
      while (!((status_read = STATUS) & (STAT_ARB_CMPL | STAT_SEL)) &&
             (jiffies < clock) && !st0x_aborted) ;

      if (!(status_read & STAT_ARB_CMPL))
      {
#if (DEBUG & PHASE_SELECTION)
        if (status_read & STAT_SEL)
          printk ("scsi%d : arbitration lost\n", hostno);
        else
          printk ("scsi%d : arbitration timeout.\n", hostno);
#endif
        WRITE_CONTROL (BASE_CMD);
        return retcode (DID_NO_CONNECT);
      };

#if (DEBUG & PHASE_SELECTION)
      printk ("scsi%d : arbitration complete\n", hostno);
#endif
#endif

/*
 *    When the SCSI device decides that we're gawking at it, it will
 *    respond by asserting BUSY on the bus.
 *
 *    Note : the Seagate ST-01/02 product manual says that we should
 *    twiddle the DATA register before the control register.    However,
 *    this does not work reliably so we do it the other way around.
 *
 *    Probably could be a problem with arbitration too, we really should
 *    try this with a SCSI protocol or logic analyzer to see what is
 *    going on.
 */
#ifdef OLDCNTDATASCEME
#ifdef SWAPCNTDATA
	cli();
      WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL |
                     (reselect ? CMD_ATTN : 0));
      WRITE_DATA ((unsigned char) ((1 << target) |
                               (controller_type == SEAGATE ? 0x80 : 0x40)));
	sti();
#else
      cli ();
      WRITE_DATA ((unsigned char) ((1 << target) |
                               (controller_type == SEAGATE ? 0x80 : 0x40)));
      WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL |
                     (reselect ? CMD_ATTN : 0));
      sti ();
#endif
#else
       tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE 
? 0x80 : 0x40));
       tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL |
                (reselect ? CMD_ATTN : 0) | CMD_BSY;
       WRITE_CONTROL(tmp_data);
       WRITE_DATA(tmp_control);
       tmp_control ^= CMD_BSY;
       WRITE_CONTROL(tmp_control);
#endif /* OLDCNTDATASCEME */
      while (!((status_read = STATUS) & STAT_BSY) && (jiffies < clock)
             && !st0x_aborted)
#if 0 && (DEBUG & PHASE_SELECTION)
      {
        temp = clock - jiffies;

        if (!(jiffies % 5))
          printk ("seagate_st0x_timeout : %d            \r", temp);
      }
      printk ("Done.                                             \n");
      printk ("scsi%d : status = %02x, seagate_st0x_timeout = %d, aborted = %02x \n",
              hostno, status_read, temp, st0x_aborted);
#else
        ;
#endif

      if ((jiffies >= clock) && !(status_read & STAT_BSY))
      {
#if (DEBUG & PHASE_SELECTION)
        printk ("scsi%d : NO CONNECT with target %d, status = %x \n",
                hostno, target, STATUS);
#endif
        return retcode (DID_NO_CONNECT);
      }

/*
 *    If we have been aborted, and we have a command in progress, IE the
 *      target still has BSY asserted, then we will reset the bus, and
 *      notify the midlevel driver to expect sense.
 */

      if (st0x_aborted)
      {
        WRITE_CONTROL (BASE_CMD);
        if (STATUS & STAT_BSY)
        {
          printk ("scsi%d : BST asserted after we've been aborted.\n",
                  hostno);
          seagate_st0x_reset (NULL, 0);
          return retcode (DID_RESET);
        }
        return retcode (st0x_aborted);
      }

/* Establish current pointers.  Take into account scatter / gather */

      if ((nobuffs = SCint->use_sg))
      {
#if (DEBUG & DEBUG_SG)
        {
          int i;

          printk ("scsi%d : scatter gather requested, using %d buffers.\n",
                  hostno, nobuffs);
          for (i = 0; i < nobuffs; ++i)
            printk ("scsi%d : buffer %d address = %08x length = %d\n",
                    hostno, i, buffer[i].address, buffer[i].length);
        }
#endif

        buffer = (struct scatterlist *) SCint->buffer;
        len = buffer->length;
        data = (unsigned char *) buffer->address;
      }
      else
      {
#if (DEBUG & DEBUG_SG)
        printk ("scsi%d : scatter gather not requested.\n", hostno);
#endif
        buffer = NULL;
        len = SCint->request_bufflen;
        data = (unsigned char *) SCint->request_buffer;
      }

#if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT))
      printk ("scsi%d : len = %d\n", hostno, len);
#endif

      break;
#ifdef LINKED
    case LINKED_RIGHT:
      break;
    case LINKED_WRONG:
      break;
#endif
  }                                     /* end of switch(reselect) */

/*
 *    There are several conditions under which we wish to send a message :
 *      1.  When we are allowing disconnect / reconnect, and need to establish
 *          the I_T_L nexus via an IDENTIFY with the DiscPriv bit set.
 *
 *      2.  When we are doing linked commands, are have the wrong I_T_L nexus
 *          established and want to send an ABORT message.
 */

/* GCC does not like an ifdef inside a macro, so do it the hard way. */
#ifdef LINKED
  WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE |
                 (((reselect == CAN_RECONNECT)
                   || (reselect == LINKED_WRONG)
                  )? CMD_ATTN : 0));
#else
  WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE |
                 (((reselect == CAN_RECONNECT)
                  )? CMD_ATTN : 0));
#endif

/*
 *    INFORMATION TRANSFER PHASE
 *
 *      The nasty looking read / write inline assembler loops we use for
 *      DATAIN and DATAOUT phases are approximately 4-5 times as fast as
 *      the 'C' versions - since we're moving 1024 bytes of data, this
 *      really adds up.
 *
 *      SJT: The nasty-looking assembler is gone, so it's slower.
 *
 */

#if ((DEBUG & PHASE_ETC) == PHASE_ETC)
  printk ("scsi%d : phase = INFORMATION TRANSFER\n", hostno);
#endif

  incommand = 1;
  transfersize = SCint->transfersize;
  underflow = SCint->underflow;

/*
 *    Now, we poll the device for status information,
 *      and handle any requests it makes.  Note that since we are unsure of
 *      how much data will be flowing across the system, etc and cannot
 *      make reasonable timeouts, that we will instead have the midlevel
 *      driver handle any timeouts that occur in this phase.
 */

  while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done)
  {
#ifdef PARITY
    if (status_read & STAT_PARITY)
    {
      printk ("scsi%d : got parity error\n", hostno);
      st0x_aborted = DID_PARITY;
    }
#endif

    if (status_read & STAT_REQ)
    {
#if ((DEBUG & PHASE_ETC) == PHASE_ETC)
      if ((newphase = (status_read & REQ_MASK)) != phase)
      {
        phase = newphase;
        switch (phase)
        {
          case REQ_DATAOUT:
            printk ("scsi%d : phase = DATA OUT\n", hostno);
            break;
          case REQ_DATAIN:
            printk ("scsi%d : phase = DATA IN\n", hostno);
            break;
          case REQ_CMDOUT:
            printk ("scsi%d : phase = COMMAND OUT\n", hostno);
            break;
          case REQ_STATIN:
            printk ("scsi%d : phase = STATUS IN\n", hostno);
            break;
          case REQ_MSGOUT:
            printk ("scsi%d : phase = MESSAGE OUT\n", hostno);
            break;
          case REQ_MSGIN:
            printk ("scsi%d : phase = MESSAGE IN\n", hostno);
            break;
          default:
            printk ("scsi%d : phase = UNKNOWN\n", hostno);
            st0x_aborted = DID_ERROR;
        }
      }
#endif
      switch (status_read & REQ_MASK)
      {
        case REQ_DATAOUT:
/*
 * If we are in fast mode, then we simply splat the data out
 * in word-sized chunks as fast as we can.
 */

#ifdef FAST
          if (!len)
          {
#if 0
            printk ("scsi%d: underflow to target %d lun %d \n", hostno,
                    target, lun);
            st0x_aborted = DID_ERROR;
            fast = 0;
#endif
            break;
          }

          if (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

/* SJT: Start. Fast Write */
#ifdef SEAGATE_USE_ASM
            __asm__(
                "cld\n\t"
#ifdef FAST32
                "shr $2, %%ecx\n\t"
                "1:\t"
                "lodsl\n\t"
                "movl %%eax, (%%edi)\n\t"
#else
                "1:\t"
                "lodsb\n\t"
                "movb %%al, (%%edi)\n\t"
#endif
                "loop 1b;"
/* output */    :
/* input */     : "D" (phys_to_virt(st0x_dr)), "S" (data), "c" (SCint->transfersize) 
/* clobbered */ : "eax", "ecx", "esi" );
#else /* SEAGATE_USE_ASM */
            {
#ifdef FAST32
              unsigned int *iop = phys_to_virt (st0x_dr);
              const unsigned int *dp = (unsigned int *) data;
              int xferlen = transfersize >> 2;
#else
              unsigned char *iop = phys_to_virt (st0x_dr);
              const unsigned char *dp = data;
              int xferlen = transfersize;
#endif
              for (; xferlen; --xferlen)
                *iop = *dp++;
            }
#endif /* SEAGATE_USE_ASM */
/* SJT: End */
            len -= transfersize;
            data += transfersize;
#if (DEBUG & DEBUG_FAST)
            printk ("scsi%d : FAST transfer complete len = %d data = %08x\n",
                    hostno, len, data);
#endif
          }
          else
#endif /* ifdef FAST */
          {
/*
 *    We loop as long as we are in a data out phase, there is data to send,
 *      and BSY is still active.
 */

/* SJT: Start. Slow Write. */
#ifdef SEAGATE_USE_ASM
/*
 *      We loop as long as we are in a data out phase, there is data to send, 
 *      and BSY is still active.
 */
/* Local variables : len = ecx , data = esi, 
                     st0x_cr_sr = ebx, st0x_dr =  edi
*/
            __asm__ (
            /* Test for any data here at all. */
                    "orl %%ecx, %%ecx\n\t"
                    "jz 2f\n\t"
                    "cld\n\t"
/*                    "movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%ebx\n\t"  */
/*                    "movl " SYMBOL_NAME_STR(st0x_dr) ", %%edi\n\t"  */
                "1:\t"
                    "movb (%%ebx), %%al\n\t"
            /* Test for BSY */
                    "test $1, %%al\n\t"
                    "jz 2f\n\t"
            /* Test for data out phase - STATUS & REQ_MASK should be 
               REQ_DATAOUT, which is 0. */
                    "test $0xe, %%al\n\t"
                    "jnz 2f\n\t"
            /* Test for REQ */      
                    "test $0x10, %%al\n\t"
                    "jz 1b\n\t"
                    "lodsb\n\t"
                    "movb %%al, (%%edi)\n\t"
                    "loop 1b\n\t"
                "2:\n"
/* output */    : "=S" (data), "=c" (len) 
/* input */     : "0" (data), "1" (len), "b" (phys_to_virt(st0x_cr_sr)), "D" (phys_to_virt(st0x_dr)) 
/* clobbered */ : "eax", "ebx", "edi"); 
#else /* SEAGATE_USE_ASM */
            while (len)
            {
              unsigned char stat;

              stat = STATUS;
              if (!(stat & STAT_BSY) || ((stat & REQ_MASK) != REQ_DATAOUT))
                break;
              if (stat & STAT_REQ)
              {
                WRITE_DATA (*data++);
                --len;
              }
            }
#endif /* SEAGATE_USE_ASM */
/* SJT: End. */
          }

          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_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 FAST
            if (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
/* SJT: Start. Fast Read */
#ifdef SEAGATE_USE_ASM
            __asm__(
                    "cld\n\t"
#ifdef FAST32
                    "shr $2, %%ecx\n\t"
                "1:\t"
                    "movl (%%esi), %%eax\n\t"
                    "stosl\n\t"
#else
                "1:\t"
                    "movb (%%esi), %%al\n\t"
                    "stosb\n\t"
#endif
                    "loop 1b\n\t"
/* output */        : 
/* input */         : "S" (phys_to_virt(st0x_dr)), "D" (data), "c" (SCint->transfersize) 
/* clobbered */     : "eax", "ecx", "edi");
#else /* SEAGATE_USE_ASM */
            {
#ifdef FAST32
              const unsigned int *iop = phys_to_virt (st0x_dr);
              unsigned int *dp = (unsigned int *) data;
              int xferlen = len >> 2;
#else
              const unsigned char *iop = phys_to_virt (st0x_dr);
              unsigned char *dp = data;
              int xferlen = len;
#endif
              for (; xferlen; --xferlen)
                *dp++ = *iop;
            }
#endif /* SEAGATE_USE_ASM */
/* SJT: End */
            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
 */

/* 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;
#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)
            {
              WRITE_DATA (*(const unsigned char *) cmnd);
              cmnd = 1 + (const 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.
 */

          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));

#if (DEBUG & (PHASE_RESELECT | PHASE_MSGOUT))
              printk ("scsi%d : sent IDENTIFY message.\n", hostno);
#endif
              break;
#ifdef LINKED
            case LINKED_WRONG:
              WRITE_DATA (ABORT);
              linked_connected = 0;
              reselect = CAN_RECONNECT;
              goto connect_loop;
#if (DEBUG & (PHASE_MSGOUT | DEBUG_LINKED))
              printk ("scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);
#endif
#endif /* LINKED */
#if (DEBUG & DEBUG_LINKED)
              printk ("correct\n");
#endif
            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:
              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;
      }                                 /* end of switch (status_read &
                                           REQ_MASK) */

#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(status_read & STAT_REQ) ends */
  }                                     /* while(((status_read = STATUS)...)
                                           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 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;
#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 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:
#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
    WRITE_CONTROL (BASE_CMD | CMD_INTR);
  }
  else
    WRITE_CONTROL (BASE_CMD);

  return retcode (st0x_aborted);
}                                       /* end of internal_command */

Generated by GNU enscript 1.6.4.