Enscript Output

extractedLnx/linux/drivers/scsi/aha152x.c_aha152x_intr.c

void aha152x_intr( int irqno, struct pt_regs * regs )
{
  unsigned int flags;
  int done=0, phase;

#if defined(DEBUG_RACE)
  enter_driver("intr");
#else
#if defined(DEBUG_INTR)
  if(aha152x_debug & debug_intr)
    printk("\naha152x: intr(), ");
#endif
#endif

  /* no more interrupts from the controller, while we busy.
     INTEN has to be restored, when we're ready to leave
     intr(). To avoid race conditions we have to return
     immediately afterwards. */
  CLRBITS( DMACNTRL0, INTEN);
  sti();  /* Yes, sti() really needs to be here */

  /* disconnected target is trying to reconnect.
     Only possible, if we have disconnected nexuses and
     nothing is occupying the bus.
  */
  if( TESTHI( SSTAT0, SELDI ) &&
      disconnected_SC &&
      ( !current_SC || ( current_SC->SCp.phase & in_selection ) )
    )
    {
      int identify_msg, target, i;

      /* Avoid conflicts when a target reconnects
	 while we are trying to connect to another. */
      if(current_SC)
	{
#if defined(DEBUG_QUEUES)
	  if(aha152x_debug & debug_queues)
	  printk("i+, ");
#endif
	  save_flags(flags);
	  cli();
	  append_SC( &issue_SC, current_SC);
	  current_SC=NULL;
	  restore_flags(flags);
	}

      /* disable sequences */
      SETPORT( SCSISEQ, 0 );
      SETPORT( SSTAT0, CLRSELDI );
      SETPORT( SSTAT1, CLRBUSFREE );

#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
      if(aha152x_debug & (debug_queues|debug_phases))
	printk("reselected, ");
#endif

      i = GETPORT(SELID) & ~(1 << this_host);
      target=0;
      if(i)
	for( ; (i & 1)==0; target++, i>>=1)
	  ;
      else
	aha152x_panic("reconnecting target unknown");

#if defined(DEBUG_QUEUES)
      if(aha152x_debug & debug_queues)
	printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
#endif
      SETPORT( SCSIID, (this_host << OID_) | target );
      SETPORT( SCSISEQ, ENRESELI );

      if(TESTLO( SSTAT0, SELDI ))
	aha152x_panic("RESELI failed");

      SETPORT( SCSISIG, P_MSGI );

      /* Get identify message */
      if((i=getphase())!=P_MSGI)
	{
	  printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
	  aha152x_panic("unknown lun");
	}
      SETPORT( SCSISEQ, 0 );

      SETPORT( SXFRCTL0, CH1);

      identify_msg = GETPORT(SCSIBUS);

      if(!(identify_msg & IDENTIFY_BASE))
	{
	  printk("target=%d, inbound message (%02x) != IDENTIFY\n",
		 target, identify_msg);
	  aha152x_panic("unknown lun");
	}

      make_acklow();
      getphase();

#if defined(DEBUG_QUEUES)
      if(aha152x_debug & debug_queues)
	printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
#endif

      save_flags(flags);
      cli();

#if defined(DEBUG_QUEUES)
      if(aha152x_debug & debug_queues)
	printk("d-, ");
#endif
      current_SC = remove_SC( &disconnected_SC,
			      target,
			      identify_msg & 0x3f );

      if(!current_SC)
	{
	  printk("lun=%d, ", identify_msg & 0x3f );
	  aha152x_panic("no disconnected command for that lun");
	}

      current_SC->SCp.phase &= ~disconnected;
      restore_flags(flags);

      SETPORT( SIMODE0, 0 );
      SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
#if defined(DEBUG_RACE)
      leave_driver("(reselected) intr");
#endif
      SETBITS( DMACNTRL0, INTEN);
      return;
    }
  
  /* Check, if we aren't busy with a command */
  if(!current_SC)
    {
      /* bus is free to issue a queued command */
      if(TESTHI( SSTAT1, BUSFREE) && issue_SC)
	{
	  save_flags(flags);
	  cli();
#if defined(DEBUG_QUEUES)
	  if(aha152x_debug & debug_queues)
	    printk("i-, ");
#endif
	  current_SC = remove_first_SC( &issue_SC );
	  restore_flags(flags);

#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
	  if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
	    printk("issuing command, ");
#endif
	  current_SC->SCp.phase = in_selection;

  #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
	  if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
	    printk("selecting %d, ", current_SC->target); 
  #endif
	  SETPORT( SCSIID, (this_host << OID_) | current_SC->target );

	  /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
	  SETPORT( SXFRCTL1, can_doparity ? (ENSPCHK|ENSTIMER) : ENSTIMER);

	  /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
	  SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
	  SETPORT( SIMODE1, ENSELTIMO );

	  /* Enable SELECTION OUT sequence */
	  SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
	
  #if defined(DEBUG_RACE)
	  leave_driver("(selecting) intr");
  #endif
	  SETBITS( DMACNTRL0, INTEN );
	  return;
	}

      /* No command we are busy with and no new to issue */
      printk("aha152x: ignoring spurious interrupt, nothing to do\n");
      return;
    }

  /* the bus is busy with something */

#if defined(DEBUG_INTR)
  if(aha152x_debug & debug_intr)
    disp_ports();
#endif

  /* we are waiting for the result of a selection attempt */
  if(current_SC->SCp.phase & in_selection)
    {
      if( TESTLO( SSTAT1, SELTO ) )
	/* no timeout */
	if( TESTHI( SSTAT0, SELDO ) )
	  {
	    /* clear BUS FREE interrupt */
	    SETPORT( SSTAT1, CLRBUSFREE);

	    /* Disable SELECTION OUT sequence */
	    CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );

	    /* Disable SELECTION OUT DONE interrupt */
	    CLRBITS(SIMODE0, ENSELDO);
	    CLRBITS(SIMODE1, ENSELTIMO);

	    if( TESTLO(SSTAT0, SELDO) )
	      {
		printk("aha152x: passing bus free condition\n");

#if defined(DEBUG_RACE)
		leave_driver("(passing bus free) intr");
#endif
		SETBITS( DMACNTRL0, INTEN);

		if(current_SC->SCp.phase & aborted)
		  {
		    abort_result=SCSI_ABORT_ERROR;
		    abortion_complete++;
		  }

		aha152x_done( DID_NO_CONNECT << 16 );
		return;
	      }
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
	    if(aha152x_debug & (debug_selection|debug_phases))
	      printk("SELDO (SELID=%x), ", GETPORT(SELID));
#endif

	    /* selection was done */
	    SETPORT( SSTAT0, CLRSELDO );

#if defined(DEBUG_ABORT)
	    if((aha152x_debug & debug_abort) && (current_SC->SCp.phase & aborted))
	      printk("(ABORT) target selected, ");
#endif

	    current_SC->SCp.phase &= ~in_selection;
	    current_SC->SCp.phase |= in_other;

#if defined(DEBUG_RACE)
	    leave_driver("(SELDO) intr");
#endif

	    SETPORT( SCSISIG, P_MSGO );

	    SETPORT( SIMODE0, 0 );
	    SETPORT( SIMODE1, ENREQINIT|ENBUSFREE );
	    SETBITS( DMACNTRL0, INTEN);
	    return;
	  }
	else
	  aha152x_panic("neither timeout nor selection\007");
      else
	{
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
	  if(aha152x_debug & (debug_selection|debug_phases))
	  printk("SELTO, ");
#endif
	  /* end selection attempt */
	  CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );

	  /* timeout */
	  SETPORT( SSTAT1, CLRSELTIMO );

	  SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
	  SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
	  SETBITS( DMACNTRL0, INTEN );
#if defined(DEBUG_RACE)
	  leave_driver("(SELTO) intr");
#endif

	  if(current_SC->SCp.phase & aborted)
	    {
#if defined(DEBUG_ABORT)
	      if(aha152x_debug & debug_abort)
		printk("(ABORT) selection timeout, ");
#endif
	      abort_result=SCSI_ABORT_ERROR;
	      abortion_complete++;
	    }

	  if( TESTLO( SSTAT0, SELINGO ) )
	    /* ARBITRATION not won */
	    aha152x_done( DID_BUS_BUSY << 16 );
	  else
	    /* ARBITRATION won, but SELECTION failed */
	    aha152x_done( DID_NO_CONNECT << 16 );
	  return;
	}
    }

  /* enable interrupt, when target leaves current phase */
  phase = getphase();
  if(!(phase & ~P_MASK))                                      /* "real" phase */
    SETPORT(SCSISIG, phase);
  SETPORT(SSTAT1, CLRPHASECHG);
  current_SC->SCp.phase =
    (current_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16 );

  /* information transfer phase */
  switch( phase )
    {
    case P_MSGO:                                               /* MESSAGE OUT */
      {
	unsigned char message;

#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
	if(aha152x_debug & (debug_intr|debug_msgo|debug_phases))
	  printk("MESSAGE OUT, ");
#endif

	if( current_SC->SCp.phase & aborted )
	  {
#if defined(DEBUG_MSGO) || defined(DEBUG_ABORT)
	    if(aha152x_debug & (debug_msgo|debug_abort))
	      printk("ABORT, ");
#endif
	    message=ABORT;
	  }
	else
	  /* If we didn't identify yet, do it. Otherwise there's nothing to do,
	     but reject (probably we got an message before, that we have to
	     reject (SDTR, WDTR, etc.) */
	  if( !(current_SC->SCp.phase & sent_ident))
	    {
	      message=IDENTIFY(can_disconnect,current_SC->lun);
#if defined(DEBUG_MSGO)
	      if(aha152x_debug & debug_msgo)
		printk("IDENTIFY (reconnect=%s;lun=%d), ", 
			can_disconnect ? "enabled" : "disabled", current_SC->lun);
#endif
	    }
	  else
	    {
	      message=MESSAGE_REJECT;
#if defined(DEBUG_MSGO)
	      if(aha152x_debug & debug_msgo)
		printk("REJECT, ");
#endif
	    }
	  
	CLRBITS( SXFRCTL0, ENDMA);

	SETPORT( SIMODE0, 0 );
	SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE );

	/* wait for data latch to become ready or a phase change */
	while( TESTLO( DMASTAT, INTSTAT ) )
	  ;

	if( TESTHI( SSTAT1, PHASEMIS ) )
	  aha152x_panic("unable to send message");

	/* Leave MESSAGE OUT after transfer */
	SETPORT( SSTAT1, CLRATNO);

	SETPORT( SCSIDAT, message );

	make_acklow();
	getphase();

	if(message==IDENTIFY(can_disconnect,current_SC->lun))
	  current_SC->SCp.phase |= sent_ident;

	if(message==ABORT)
	  {
	    /* revive abort(); abort() enables interrupts */
	    abort_result=SCSI_ABORT_SUCCESS;
	    abortion_complete++;

	    current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));

	    /* exit */
	    SETBITS( DMACNTRL0, INTEN );
#if defined(DEBUG_RACE)
	    leave_driver("(ABORT) intr");
#endif
	    aha152x_done(DID_ABORT<<16);
	    return;
	  }
      }
      break;

    case P_CMD:                                          /* COMMAND phase */
#if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
      if(aha152x_debug & (debug_intr|debug_cmd|debug_phases))
	printk("COMMAND, ");
#endif
      if( !(current_SC->SCp.sent_command) )
	{
	  if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
	    printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n",
		   GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));

	  /* reset fifo and enable writes */
	  SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
	  SETPORT(DMACNTRL0, ENDMA|WRITE_READ);

	  /* clear transfer count and scsi fifo */
	  SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
	  SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
  
	  /* missing phase raises INTSTAT */
	  SETPORT( SIMODE0, 0 );
	  SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
  
#if defined(DEBUG_CMD)
	  if(aha152x_debug & debug_cmd)
	    printk("waiting, ");
#endif
	  /* wait for FIFO to get empty */
	  while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
	    ;
  
	  if( TESTHI( SSTAT1, PHASEMIS ) )
	    aha152x_panic("target left COMMAND phase");

#if defined(DEBUG_CMD)
	  if(aha152x_debug & debug_cmd)
	  {
	    printk("DFIFOEMP, outsw (%d bytes, %d words), ",
		   current_SC->cmd_len, current_SC->cmd_len >> 1 );
	    disp_ports();
	  }
#endif
  
	  outsw( DATAPORT, &current_SC->cmnd, current_SC->cmd_len >> 1 );

#if defined(DEBUG_CMD)
	  if(aha152x_debug & debug_cmd)
	  {
	    printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
	    disp_ports();
	  }
#endif

#if defined(DEBUG_CMD)
	  if(aha152x_debug & debug_cmd)
	    printk("waiting for SEMPTY, ");
#endif

	  /* wait for SCSI FIFO to get empty.
	     very important to send complete commands. */
	  while( TESTLO ( SSTAT2, SEMPTY ) )
	    ;

#if defined(DEBUG_CMD)
	  if(aha152x_debug & debug_cmd)
	    printk("SEMPTY, ");
#endif

	  CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
	  /* transfer can be considered ended, when SCSIEN reads back zero */
	  while( TESTHI( SXFRCTL0, SCSIEN ) )
	    ;

#if defined(DEBUG_CMD)
	  if(aha152x_debug & debug_cmd)
	    printk("!SEMPTY, ");
#endif

	  CLRBITS(DMACNTRL0, ENDMA);

#if defined(DEBUG_CMD) || defined(DEBUG_INTR)
	  if(debug_cmd & debug_intr)
	    printk("sent %d/%d command bytes, ", GETSTCNT(),
		   current_SC->cmd_len);
#endif

	}
      else
	aha152x_panic("Nothing to sent while in COMMAND OUT");
      break;

    case P_MSGI:                                          /* MESSAGE IN phase */
#if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
      if(aha152x_debug & (debug_intr|debug_msgi|debug_phases))
	printk("MESSAGE IN, ");
#endif
      SETPORT( SXFRCTL0, CH1);

      SETPORT( SIMODE0, 0);
      SETPORT( SIMODE1, ENBUSFREE);
  
      while( phase == P_MSGI ) 
	{
	  current_SC->SCp.Message = GETPORT( SCSIBUS );
	  switch(current_SC->SCp.Message)
	    {
	    case DISCONNECT:
#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
	      if(aha152x_debug & (debug_msgi|debug_phases))
		printk("target disconnected, ");
#endif
	      current_SC->SCp.Message = 0;
	      current_SC->SCp.phase   |= disconnected;
	      if(!can_disconnect)
		aha152x_panic("target was not allowed to disconnect");
	      break;
	
	    case COMMAND_COMPLETE:
#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
	      if(aha152x_debug & (debug_msgi|debug_phases))
		printk("inbound message ( COMMAND COMPLETE ), ");
#endif
	      done++;
	      break;

	    case MESSAGE_REJECT:
#if defined(DEBUG_MSGI)
	      if(aha152x_debug & debug_msgi)
		printk("inbound message ( MESSAGE REJECT ), ");
#endif
	      break;

	    case SAVE_POINTERS:
#if defined(DEBUG_MSGI)
	      if(aha152x_debug & debug_msgi)
		printk("inbound message ( SAVE DATA POINTERS ), ");
#endif
	      break;

	    case EXTENDED_MESSAGE:
	      { 
		int           i, code;

#if defined(DEBUG_MSGI)
		if(aha152x_debug & debug_msgi)
		  printk("inbound message ( EXTENDED MESSAGE ), ");
#endif
		make_acklow();
		if(getphase()!=P_MSGI)
		  break;
  
		i=GETPORT(SCSIBUS);

#if defined(DEBUG_MSGI)
		if(aha152x_debug & debug_msgi)
		  printk("length (%d), code ( ", i);
#endif

		make_acklow();
		if(getphase()!=P_MSGI)
		  break;

		code = GETPORT(SCSIBUS);

		switch( code )
		  {
		  case 0x00:
#if defined(DEBUG_MSGI)
		    if(aha152x_debug & debug_msgi)
		      printk("MODIFY DATA POINTER ");
#endif
		    SETPORT(SCSISIG, P_MSGI|ATNO);
		    break;
		  case 0x01:
#if defined(DEBUG_MSGI)
		    if(aha152x_debug & debug_msgi)
		      printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
#endif
		    SETPORT(SCSISIG, P_MSGI|ATNO);
		    break;
		  case 0x02:
#if defined(DEBUG_MSGI)
		    if(aha152x_debug & debug_msgi)
		      printk("EXTENDED IDENTIFY ");
#endif
		    break;
		  case 0x03:
#if defined(DEBUG_MSGI)
		    if(aha152x_debug & debug_msgi)
		      printk("WIDE DATA TRANSFER REQUEST ");
#endif
		    SETPORT(SCSISIG, P_MSGI|ATNO);
		    break;
		  default:
#if defined(DEBUG_MSGI)
		    if(aha152x_debug & debug_msgi)
		      if( code & 0x80 )
			printk("reserved (%d) ", code );
		      else
			printk("vendor specific (%d) ", code);
#endif
		    SETPORT(SCSISIG, P_MSGI|ATNO);
		    break;
		  }
#if defined(DEBUG_MSGI)
		if(aha152x_debug & debug_msgi)
		  printk(" ), data ( ");
#endif
		while( --i && (make_acklow(), getphase()==P_MSGI))
		  {
#if defined(DEBUG_MSGI)
		    if(aha152x_debug & debug_msgi)
		      printk("%x ", GETPORT(SCSIBUS) );
#else
		    GETPORT(SCSIBUS);
#endif
		  }
#if defined(DEBUG_MSGI)
		if(aha152x_debug & debug_msgi)
		  printk(" ), ");
#endif
		/* We reject all extended messages. To do this
		   we just enter MSGO by asserting ATN. Since
		   we have already identified a REJECT message
		   will be sent. */
		SETPORT(SCSISIG, P_MSGI|ATNO);
	      }
	      break;
       
	    default:
	      printk("unsupported inbound message %x, ", current_SC->SCp.Message);
	      break;

	    }

	  make_acklow();
	  phase=getphase();
	} 

      /* clear SCSI fifo on BUSFREE */
      if(phase==P_BUSFREE)
	SETPORT(SXFRCTL0, CH1|CLRCH1);

      if(current_SC->SCp.phase & disconnected)
	{
	  save_flags(flags);
	  cli();
#if defined(DEBUG_QUEUES)
	  if(aha152x_debug & debug_queues)
	    printk("d+, ");
#endif
	  append_SC( &disconnected_SC, current_SC);
	  current_SC = NULL;
	  restore_flags(flags);

	  SETBITS( SCSISEQ, ENRESELI );

	  SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
	  SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);

	  SETBITS( DMACNTRL0, INTEN );
	  return;
	}
      break;

    case P_STATUS:                                         /* STATUS IN phase */
#if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
      if(aha152x_debug & (debug_status|debug_intr|debug_phases))
	printk("STATUS, ");
#endif
      SETPORT( SXFRCTL0, CH1);

      SETPORT( SIMODE0, 0 );
      SETPORT( SIMODE1, ENREQINIT|ENBUSFREE );

      if( TESTHI( SSTAT1, PHASEMIS ) )
	printk("aha152x: passing STATUS phase");
	
      current_SC->SCp.Status = GETPORT( SCSIBUS );
      make_acklow();
      getphase();

#if defined(DEBUG_STATUS)
      if(aha152x_debug & debug_status)
      {
	printk("inbound status ");
	print_status( current_SC->SCp.Status );
	printk(", ");
      }
#endif
      break;

    case P_DATAI:                                            /* DATA IN phase */
      {
	int fifodata, data_count, done;

#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
	if(aha152x_debug & (debug_datai|debug_intr|debug_phases))
	  printk("DATA IN, ");
#endif

	if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
	  printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
		 GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));

	/* reset host fifo */
	SETPORT(DMACNTRL0, RSTFIFO);
	SETPORT(DMACNTRL0, RSTFIFO|ENDMA);

	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN );

	SETPORT( SIMODE0, 0 );
	SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );

	/* done is set when the FIFO is empty after the target left DATA IN */
	done=0;
      
	/* while the target stays in DATA to transfer data */
	while ( !done ) 
	  {
#if defined(DEBUG_DATAI)
	    if(aha152x_debug & debug_datai)
	      printk("expecting data, ");
#endif
	    /* wait for PHASEMIS or full FIFO */
	    while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) )
	      ;

	    if( TESTHI( DMASTAT, DFIFOFULL ) )
	      fifodata=GETPORT(FIFOSTAT);
	    else
	      {
		/* wait for SCSI fifo to get empty */
		while( TESTLO( SSTAT2, SEMPTY ) )
		  ;

		/* rest of data in FIFO */
		fifodata=GETPORT(FIFOSTAT);
#if defined(DEBUG_DATAI)
		if(aha152x_debug & debug_datai)
		  printk("last transfer, ");
#endif
		done=1;
	      }
  
#if defined(DEBUG_DATAI)
	    if(aha152x_debug & debug_datai)
	      printk("fifodata=%d, ", fifodata);
#endif

	    while( fifodata && current_SC->SCp.this_residual )
	      {
		data_count=fifodata;
  
		/* limit data transfer to size of first sg buffer */
		if (data_count > current_SC->SCp.this_residual)
		  data_count = current_SC->SCp.this_residual;
  
		fifodata -= data_count;

#if defined(DEBUG_DATAI)
		if(aha152x_debug & debug_datai)
		  printk("data_count=%d, ", data_count);
#endif
  
		if(data_count&1)
		  {
		    /* get a single byte in byte mode */
		    SETBITS(DMACNTRL0, _8BIT );
		    *current_SC->SCp.ptr++ = GETPORT( DATAPORT );
		    current_SC->SCp.this_residual--;
		  }
		if(data_count>1)
		  {
		    CLRBITS(DMACNTRL0, _8BIT );
		    data_count >>= 1; /* Number of words */
		    insw( DATAPORT, current_SC->SCp.ptr, data_count );
#if defined(DEBUG_DATAI)
		    if(aha152x_debug & debug_datai)
/* show what comes with the last transfer */
		      if(done)
			{
			  int           i;
			  unsigned char *data;
  
			  printk("data on last transfer (%d bytes: ",
				 2*data_count);
			  data = (unsigned char *) current_SC->SCp.ptr;
			  for( i=0; i<2*data_count; i++)
			    printk("%2x ", *data++);
			  printk("), ");
			}
#endif
		    current_SC->SCp.ptr           += 2 * data_count;
		    current_SC->SCp.this_residual -= 2 * data_count;
		  }
	      
		/* if this buffer is full and there are more buffers left */
		if (!current_SC->SCp.this_residual &&
		     current_SC->SCp.buffers_residual)
		  {
		    /* advance to next buffer */
		    current_SC->SCp.buffers_residual--;
		    current_SC->SCp.buffer++;
		    current_SC->SCp.ptr =
		      current_SC->SCp.buffer->address;
		    current_SC->SCp.this_residual =
		      current_SC->SCp.buffer->length;
		  } 
	      }
 
	    /*
	     * Fifo should be empty
	     */
	    if(fifodata>0)
	      {
		printk("aha152x: more data than expected (%d bytes)\n",
		       GETPORT(FIFOSTAT));
		SETBITS(DMACNTRL0, _8BIT );
		printk("aha152x: data ( ");
		while(fifodata--)
		  printk("%2x ", GETPORT( DATAPORT ));
		printk(")\n");
	      }

#if defined(DEBUG_DATAI)
	    if(aha152x_debug & debug_datai)
	      if(!fifodata)
		printk("fifo empty, ");
	      else
		printk("something left in fifo, ");
#endif
	  }

#if defined(DEBUG_DATAI)
	if((aha152x_debug & debug_datai) && (current_SC->SCp.buffers_residual || current_SC->SCp.this_residual))
	  printk("left buffers (buffers=%d, bytes=%d), ",
		 current_SC->SCp.buffers_residual, 
		 current_SC->SCp.this_residual);
#endif
	/* transfer can be considered ended, when SCSIEN reads back zero */
	CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
	while( TESTHI( SXFRCTL0, SCSIEN ) )
	  ;
	CLRBITS(DMACNTRL0, ENDMA );

#if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
	if(aha152x_debug & (debug_datai|debug_intr))
	  printk("got %d bytes, ", GETSTCNT());
#endif

	current_SC->SCp.have_data_in++;
      }
      break;

    case P_DATAO:                                           /* DATA OUT phase */
      {
	int data_count;

#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
	if(aha152x_debug & (debug_datao|debug_intr|debug_phases))
	  printk("DATA OUT, ");
#endif
#if defined(DEBUG_DATAO)
	if(aha152x_debug & debug_datao)
	  printk("got data to send (bytes=%d, buffers=%d), ",
		 current_SC->SCp.this_residual,
		 current_SC->SCp.buffers_residual );
#endif

	if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) )
	  {
	    printk("%d(%d) left in FIFO, ", GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT) );
	    aha152x_panic("FIFO should be empty");
	  }

	SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
	SETPORT(DMACNTRL0, ENDMA|WRITE_READ);

	SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
	SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
 
	SETPORT( SIMODE0, 0 );
	SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );

	/* while current buffer is not empty or
	   there are more buffers to transfer */
	while( TESTLO( SSTAT1, PHASEMIS ) &&
		 (current_SC->SCp.this_residual ||
		  current_SC->SCp.buffers_residual) )
	  {
#if defined(DEBUG_DATAO)
	    if(aha152x_debug & debug_datao)
	      printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
		     current_SC->SCp.this_residual,
		     current_SC->SCp.buffers_residual);
#endif
	    /* transfer rest of buffer, but max. 128 byte */
	    data_count = current_SC->SCp.this_residual > 128 ?
			 128 : current_SC->SCp.this_residual ;

#if defined(DEBUG_DATAO)
	    if(aha152x_debug & debug_datao)
	      printk("data_count=%d, ", data_count);
#endif
  
	    if(data_count&1)
	      {
		/* put a single byte in byte mode */
		SETBITS(DMACNTRL0, _8BIT );
		SETPORT(DATAPORT, *current_SC->SCp.ptr++);
		current_SC->SCp.this_residual--;
	      }
	    if(data_count>1)
	      {
		CLRBITS(DMACNTRL0, _8BIT );
		data_count >>= 1; /* Number of words */
		outsw( DATAPORT, current_SC->SCp.ptr, data_count );
		current_SC->SCp.ptr           += 2 * data_count;
		current_SC->SCp.this_residual -= 2 * data_count;
	      }

	    /* wait for FIFO to get empty */
	    while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
	      ;

#if defined(DEBUG_DATAO)
	    if(aha152x_debug & debug_datao)
	      printk("fifo (%d bytes), transfered (%d bytes), ",
		     GETPORT(FIFOSTAT), GETSTCNT() );
#endif

	    /* if this buffer is empty and there are more buffers left */
	    if ( TESTLO( SSTAT1, PHASEMIS ) &&
		 !current_SC->SCp.this_residual &&
		  current_SC->SCp.buffers_residual)
	      {
		 /* advance to next buffer */
		 current_SC->SCp.buffers_residual--;
		 current_SC->SCp.buffer++;
		 current_SC->SCp.ptr =
		   current_SC->SCp.buffer->address;
		 current_SC->SCp.this_residual =
		 current_SC->SCp.buffer->length;
	      }
	  }

	if ( current_SC->SCp.this_residual ||
	     current_SC->SCp.buffers_residual )
	  {
	    /* target leaves DATA OUT for an other phase
	       (perhaps disconnect) */

	    /* data in fifos has to be resend */
	    data_count = GETPORT(SSTAT2) & (SFULL|SFCNT);

	    data_count += GETPORT(FIFOSTAT) ;
	    current_SC->SCp.ptr           -= data_count;
	    current_SC->SCp.this_residual += data_count;
#if defined(DEBUG_DATAO)
	    if(aha152x_debug & debug_datao)
	      printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
		     current_SC->SCp.this_residual,
		     current_SC->SCp.buffers_residual,
		     data_count );
#endif
	    SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
	    CLRBITS(SXFRCTL0, SCSIEN|DMAEN );
	    CLRBITS(DMACNTRL0, ENDMA);
	  }
	else
	  {
#if defined(DEBUG_DATAO)
	    if(aha152x_debug & debug_datao)
	      printk("waiting for SCSI fifo to get empty, ");
#endif
	    /* wait for SCSI fifo to get empty */
	    while( TESTLO( SSTAT2, SEMPTY ) )
	      ;
#if defined(DEBUG_DATAO)
	    if(aha152x_debug & debug_datao)
	      printk("ok, left data (bytes=%d, buffers=%d) ",
		     current_SC->SCp.this_residual,
		     current_SC->SCp.buffers_residual);
#endif
	    CLRBITS(SXFRCTL0, SCSIEN|DMAEN);

	    /* transfer can be considered ended, when SCSIEN reads back zero */
	    while( TESTHI( SXFRCTL0, SCSIEN ) )
	      ;

	    CLRBITS(DMACNTRL0, ENDMA);
	  }

#if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
	if(aha152x_debug & (debug_datao|debug_intr))
	  printk("sent %d data bytes, ", GETSTCNT() );
#endif
      }
      break;

    case P_BUSFREE:                                                /* BUSFREE */
#if defined(DEBUG_RACE)
      leave_driver("(BUSFREE) intr");
#endif
#if defined(DEBUG_PHASES)
      if(aha152x_debug & debug_phases)
	printk("unexpected BUS FREE, ");
#endif
      current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));

      aha152x_done( DID_ERROR << 16 );               /* Don't know any better */
      return;
      break;

    case P_PARITY:                              /* parity error in DATA phase */
#if defined(DEBUG_RACE)
      leave_driver("(DID_PARITY) intr");
#endif
      printk("PARITY error in DATA phase, ");

      current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));

      SETBITS( DMACNTRL0, INTEN );
      aha152x_done( DID_PARITY << 16 );
      return;
      break;

    default:
      printk("aha152x: unexpected phase\n");
      break;
    }

  if(done)
    {
#if defined(DEBUG_INTR)
      if(aha152x_debug & debug_intr)
	printk("command done.\n");
#endif
#if defined(DEBUG_RACE)
      leave_driver("(done) intr");
#endif

      SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
      SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
      SETPORT(SCSISEQ, disconnected_SC ? ENRESELI : 0 );

      SETBITS( DMACNTRL0, INTEN );

      aha152x_done(   (current_SC->SCp.Status  & 0xff)
		    | ( (current_SC->SCp.Message & 0xff) << 8)
		    | ( DID_OK << 16) );

#if defined(DEBUG_RACE)
      printk("done returned (DID_OK: Status=%x; Message=%x).\n",
	     current_SC->SCp.Status, current_SC->SCp.Message);
#endif
      return;
    }

  if(current_SC)
    current_SC->SCp.phase |= 1<<16 ;

  SETPORT( SIMODE0, 0 );
  SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
#if defined(DEBUG_INTR)
  if(aha152x_debug & debug_intr)
    disp_enintr();
#endif
#if defined(DEBUG_RACE)
  leave_driver("(PHASEEND) intr");
#endif

  SETBITS( DMACNTRL0, INTEN);
  return;
}

Generated by GNU enscript 1.6.4.