Subject: Patches to seagate driver (includes FD 840,880 support)
To: None <wilko@yedi.iaf.nl, rknier@qgraph.com, phil@rivendell.apana.org.au,>
From: Kent Palmkvist <kentp@isy.liu.se>
List: netbsd-bugs
Date: 12/20/1994 10:09:36
Hello.

This is a patch to the seagate driver to fix 2 problems and adds a little
feature. It applies to both FreeBSD and 386BSD 0.1 and (probably) NetBSD. The
patch has been done relative the source in FreeBSD 2.0R, but I think it is
almost identical in FreeBSD 1.1.5.

1) It adds support for Future Domain TMC 840, 841, 880, and 881. NOTE: THIS HAS
NOT BEEN TESTED!! The bootcode cannot detect these card types, so the card type
FD840 must be hardcoded into the driver by altering the probe code. I would
like to include some BIOS signatures (if the card type has onboard ROM) into
the driver to make it autodetect the card type. Another alternative is to add
some flag in the config file (how?). If this patch is added, then the FAQ is
then correct in saying that all Future Domain 8xx/950 cards are supported (as
far as I know).

2) Some SCSI devices are slow in removing the REQUEST signal. The ACK signal is
not controlled directly by software, so after writing a byte, there is no way
the software can distinguish if the REQUEST active signal is due to the device
not removing it yet, or if the device has already removed and reissued the
REQUEST signal. The solution is to wait for the device to remove REQUEST for
approx. 10 microseconds, and if it is not removed, we assume that the active
REQUEST is a new one. The problem seems to only occur during CMDOUT phase (at
least with my hardware setup).

Extra feature: It now checks for parity errors a bit more often. (I know, as I
have got some errors indicated myself, but have not been able to find any data
corruption.) This is a questionable feature, so please remove the added check
(easily spotted in the patch file).

Due to the pending vacation, I will not have access to the newsgroups, and my
response to mail will be slow.

Regards

/Kent

kentp@isy.liu.se


*** seagate.c.orig      Sun Dec 18 15:12:09 1994
--- seagate.c   Tue Dec 20 00:12:03 1994
***************
*** 131,142 ****
  /* #define SEADEBUG2  1 */    /* Display a lot about timeouts etc */
  /* #define SEADEBUG3  1 */
  /* #define SEADEBUG4  1 */
! /* #define SEADEBUG5  1 */
  /* #define SEADEBUG6  1 */    /* Display info about queue-lengths */
  /* #define SEADEBUG7  1 */    /* Extra check on STATUS before phase check */
  /* #define SEADEBUG8  1 */    /* Disregard non-BSY state in
                                   sea_information_transfer */
  /* #define SEADEBUG9  1 */    /* Enable printouts */
  /* #define SEADEBUG11 1 */    /* stop everything except access to scsi id 1 */
  /* #define SEADEBUG15 1 */    /* Display every byte sent/received */

--- 131,143 ----
  /* #define SEADEBUG2  1 */    /* Display a lot about timeouts etc */
  /* #define SEADEBUG3  1 */
  /* #define SEADEBUG4  1 */
! /* #define SEADEBUG5  1 */    /* Display trace code of calls to sea_main */
  /* #define SEADEBUG6  1 */    /* Display info about queue-lengths */
  /* #define SEADEBUG7  1 */    /* Extra check on STATUS before phase check */
  /* #define SEADEBUG8  1 */    /* Disregard non-BSY state in
                                   sea_information_transfer */
  /* #define SEADEBUG9  1 */    /* Enable printouts */
+ /* #define SEADEBUG10 1 */    /* display status during wait in sea_poll */
  /* #define SEADEBUG11 1 */    /* stop everything except access to scsi id 1 */
  /* #define SEADEBUG15 1 */    /* Display every byte sent/received */

***************
*** 191,200 ****
        #define BASE_CMD (CMD_INTR)
  #endif

! #define       SEAGATE 1
! #define FD    2

!
/***************************************************************************
***
   *    This should be placed in a more generic file (presume in /sys/scsi)
   *    Message codes:
   */
--- 192,202 ----
        #define BASE_CMD (CMD_INTR)
  #endif

! #define       SEAGATE 1   /* seagate ST01/02 */
! #define FD    2   /* Future Domain TMC-950, TMC-885 */
! #define FD840   3   /* Future Domain TMC-840,841,880,881 */

! /*****************************************************************************
   *    This should be placed in a more generic file (presume in /sys/scsi)
   *    Message codes:
   */
***************
*** 235,241 ****
  struct        sea_data
  {
        caddr_t basemaddr;      /* Base address for card */
!       char    ctrl_type;      /* FD or SEAGATE */
        caddr_t st0x_cr_sr;     /* Address of control and status register */
        caddr_t st0x_dr;        /* Address of data register */
        u_short vect;           /* interrupt vector for this card */
--- 237,243 ----
  struct        sea_data
  {
        caddr_t basemaddr;      /* Base address for card */
!       char    ctrl_type;      /* FD, FD840 or SEAGATE */
        caddr_t st0x_cr_sr;     /* Address of control and status register */
        caddr_t st0x_dr;        /* Address of data register */
        u_short vect;           /* interrupt vector for this card */
***************
*** 510,518 ****

    /* Find controller and data memory addresses */
    sea->st0x_cr_sr = (void *) (((unsigned char *) sea->basemaddr) +
!                             ((sea->ctrl_type == SEAGATE) ? 0x1a00 : 0x1c00));
    sea->st0x_dr = (void *) (((unsigned char *) sea->basemaddr) +
!                          ((sea->ctrl_type == SEAGATE) ? 0x1c00 : 0x1e00));

    /* Test controller RAM (works the same way on future domain cards?) */
    *(sea->basemaddr + SEAGATERAMOFFSET) = 0xa5;
--- 512,520 ----

    /* Find controller and data memory addresses */
    sea->st0x_cr_sr = (void *) (((unsigned char *) sea->basemaddr) +
!                             ((sea->ctrl_type != FD) ? 0x1a00 : 0x1c00));
    sea->st0x_dr = (void *) (((unsigned char *) sea->basemaddr) +
!                          ((sea->ctrl_type != FD) ? 0x1c00 : 0x1e00));

    /* Test controller RAM (works the same way on future domain cards?) */
    *(sea->basemaddr + SEAGATERAMOFFSET) = 0xa5;
***************
*** 978,984 ****
    int unit;
    int oldpri;

! #ifdef SEADEBUG2
    printf(".");
  #endif

--- 980,986 ----
    int unit;
    int oldpri;

! #ifdef SEADEBUG5
    printf(".");
  #endif

***************
*** 992,998 ****
          sea=seadata[++unit]) {
        oldpri = splbio();
        if (!sea->connected) {
! #ifdef SEADEBUG2
        printf(".2");
  #endif
        /*
--- 994,1000 ----
          sea=seadata[++unit]) {
        oldpri = splbio();
        if (!sea->connected) {
! #ifdef SEADEBUG5
        printf(".2");
  #endif
        /*
***************
*** 1000,1006 ****
         * target that's not busy.
         */
        for (tmp = sea->issue_queue, prev = NULL; tmp ;
!            prev = tmp, tmp = tmp->next)
          /* When we find one, remove it from the issue queue. */
          if (!(sea->busy[tmp->xfer->sc_link->target] &
                (1 << tmp->xfer->sc_link->lun))) {
--- 1002,1008 ----
         * target that's not busy.
         */
        for (tmp = sea->issue_queue, prev = NULL; tmp ;
!            prev = tmp, tmp = tmp->next) {
          /* When we find one, remove it from the issue queue. */
          if (!(sea->busy[tmp->xfer->sc_link->target] &
                (1 << tmp->xfer->sc_link->lun))) {
***************
*** 1054,1059 ****
--- 1056,1070 ----
              printf("sea_main: select failed\n");
            }
          } /* if target/lun is not busy */
+       } /* for(issue_queue) */
+       if (!(sea->connected)) {   /* check for reselection phase */
+         if ((STATUS & (STAT_SEL | STAT_IO)) == (STAT_SEL | STAT_IO)) {
+ #ifdef SEADEBUG2
+           printf(".9%x",STATUS);
+ #endif
+           sea_reselect(sea);
+         }
+       }
        } /* if (!sea->connected) */

        if (sea->connected) {   /* we are connected. Do the task */
***************
*** 1294,1308 ****

    do {
      /* wait for assertion of REQ, after which the phase bits will be valid */
!     for(timeout = 0; timeout < 5000000L ; timeout++)
        if ((tmp = STATUS) & STAT_REQ)
        break;
      if (!(tmp & STAT_REQ)) {
!       printf("sea_transfer_pio: timeout waiting for STAT_REQ\n");
        break;
      }

      /* check for phase mismatch */
      /* Reached if the target decides that it has finished the transfer */
      if ((tmp & REQ_MASK) != p) {
  #ifdef SEADEBUG1
--- 1305,1324 ----

    do {
      /* wait for assertion of REQ, after which the phase bits will be valid */
!     for(timeout = 0; timeout < 50000L ; timeout++)
        if ((tmp = STATUS) & STAT_REQ)
        break;
      if (!(tmp & STAT_REQ)) {
!       printf("sea_transfer_pio: timeout waiting for
STAT_REQ,s=%x,p=%x,c=%x\n",tmp,p,c);
        break;
      }

      /* check for phase mismatch */
+     /* compensate for FD840 cards */
+     if(sea->ctrl_type == FD840) {
+       tmp = ((0x08 & tmp) >> 2) | ((0x02 & tmp) << 2) | (0xf5 & tmp);
+     }
+
      /* Reached if the target decides that it has finished the transfer */
      if ((tmp & REQ_MASK) != p) {
  #ifdef SEADEBUG1
***************
*** 1326,1342 ****
       * should drop ATN on the last byte of the message phase
       * after REQ has been asserted for the handshake but before
       * the initiator raises ACK.
!      * Don't know how to accomplish this on the ST01/02
       */
      /* We don't mind right now. */

!     /* The st01 code doesn't wait for STAT_REQ to be deasserted. Is this
ok? */
! /*    for(timeout=0;timeout<200000L;timeout++)
!       if(!(STATUS & STAT_REQ))
!         break;
!     if(STATUS & STAT_REQ)
!       printf("timeout on wait for !STAT_REQ"); */
! /*      printf("*"); */
    } while (--c);

    *count = c;
--- 1342,1369 ----
       * should drop ATN on the last byte of the message phase
       * after REQ has been asserted for the handshake but before
       * the initiator raises ACK.
!      * This should be done by having the caller of sea_transfer_pio to first
!      * check for MSGOUT phase and then remove the ATN before calling, as the
!      * msg is only one byte long
       */
      /* We don't mind right now. */

!     /* have problems with a drive. Seems to be data overrun in command phase
!      * because the phase does not change. We now wait for STAT_REQ to go low.
!      * STAT_REQ may already been low and returned back to high, so we dont
!      * wait very long.
!      */
!     if (p == REQ_CMDOUT) {
!     /* Fix for problem with recognizing if this STAT_REQ is the old or new */
!       for(timeout=0;timeout<10L;timeout++) {
!       if(!(STATUS & STAT_REQ))
!         break;
!       DELAY(1);
!       }
! #ifdef SEADEBUG2
!       printf("-a%x",timeout);
! #endif
!     }
    } while (--c);

    *count = c;
***************
*** 1456,1461 ****
--- 1483,1489 ----
        break;
    }

+   /* remove attn when msg out phase encountered */
    CONTROL = BASE_CMD | CMD_DRVR_ENABLE;

  #if SEADEBUG2 || SEADEBUG9
***************
*** 1669,1685 ****

  int sea_poll(int unit, struct scsi_xfer *xs, struct sea_scb *scb)
  {
!   int count = 500; /* xs->timeout; */
    int oldpri;

  #ifdef SEADEBUG2
  /*    printf("sea_poll called\n"); */
!   printf("?");
  #endif

    while (count) {
      /* try to do something */
      oldpri = splbio();
      if (!main_running) {
        main_running = 1;
        sea_main();
--- 1697,1717 ----

  int sea_poll(int unit, struct scsi_xfer *xs, struct sea_scb *scb)
  {
!   int count = 50000; /* xs->timeout; */
!   struct sea_data *sea = seadata[unit];
    int oldpri;

  #ifdef SEADEBUG2
  /*    printf("sea_poll called\n"); */
!   printf("?0%x",main_running);
  #endif

    while (count) {
      /* try to do something */
      oldpri = splbio();
+ #ifdef SEADEBUG10
+     printf("?1%x %x",STATUS,main_running);
+ #endif
      if (!main_running) {
        main_running = 1;
        sea_main();
***************
*** 1775,1781 ****
   */
  static void sea_information_transfer (struct sea_data *sea)
  {
!   long int timeout;
    int unit = sea->sc_link.adapter_unit;
    unsigned char msgout = MSG_NOP;
    int32 len;
--- 1807,1813 ----
   */
  static void sea_information_transfer (struct sea_data *sea)
  {
!   long int timeout,timeout2;
    int unit = sea->sc_link.adapter_unit;
    unsigned char msgout = MSG_NOP;
    int32 len;
***************
*** 1792,1802 ****

    for(timeout = 0; timeout < 10000000L ; timeout++) {
      tmp = STATUS;
!     if (!(tmp & STAT_BSY)) {
! /*      for(loop=0;loop < 20 ; loop++) {
!         if((tmp=STATUS) & STAT_BSY)
!           break;
!       } */
  #ifndef SEADEBUG8
        if(!(tmp & STAT_BSY)) {
          printf("sea: !STAT_BSY unit in data transfer!\n");
--- 1824,1842 ----

    for(timeout = 0; timeout < 10000000L ; timeout++) {
      tmp = STATUS;
!
! #ifdef PARITY
!     /* check for parity errors (don't handle this error yet) */
!     if (tmp & STAT_PARITY) {
!       printf("sea_information_transfer: parity error detected!\n");
!     }
! #endif
!
!     if (!(tmp & STAT_BSY)) {           /* if not busy, check a few times */
!       for(loop=0;loop < 20 ; loop++) {
!         if ((tmp=STATUS) & STAT_BSY)
!         break;
!       }
  #ifndef SEADEBUG8
        if(!(tmp & STAT_BSY)) {
          printf("sea: !STAT_BSY unit in data transfer!\n");
***************
*** 1809,1814 ****
--- 1849,1859 ----
        }
  #endif
      }
+
+     /* swap bits for support for TMC840 etc */
+     if(sea->ctrl_type == FD840) {
+       tmp = ((0x08 & tmp) >> 2) | ((0x02 & tmp) << 2) | (0xf5 & tmp);
+     }

      /* we only have a valid SCSI phase when REQ is asserted */
      if (tmp & STAT_REQ) {
***************
*** 1817,1826 ****
        old_phase = phase;
        }

! #ifdef SEADEBUG7
        printf("!2%x", phase);
        for(loop=0;loop < 20; loop++) {
          phase = STATUS;
          printf("!6%x",phase);
          phase = phase & REQ_MASK;
        }
--- 1862,1879 ----
        old_phase = phase;
        }

! #ifdef SEADEBUG2
        printf("!2%x", phase);
+ #endif
+
+ #ifdef SEADEBUG7
        for(loop=0;loop < 20; loop++) {
          phase = STATUS;
+       /* swap bits for support for TMC840 etc */
+       if(sea->ctrl_type == FD840) {
+         phase = ((0x08 & phase) >> 2) | ((0x02 & phase) << 2)
+           | (0xf5 & phase);
+       }
          printf("!6%x",phase);
          phase = phase & REQ_MASK;
        }
***************
*** 1843,1853 ****
  #ifdef SEA_BLINDTRANSFER
          if (scb->datalen && !(scb->datalen % BLOCK_SIZE)) {
            while (scb->datalen) {
!             for(timeout = 0; timeout < 5000000L ; timeout++)
                if((tmp = STATUS) & STAT_REQ)
                  break;
              if(!(tmp & STAT_REQ)) {
!               printf("sea_transfer_pio: timeout waiting for STAT_REQ\n");
                /* getchar(); */
              }
              if((tmp & REQ_MASK) != phase) {
--- 1896,1906 ----
  #ifdef SEA_BLINDTRANSFER
          if (scb->datalen && !(scb->datalen % BLOCK_SIZE)) {
            while (scb->datalen) {
!             for(timeout2 = 0; timeout2 < 5000000L ; timeout2++)
                if((tmp = STATUS) & STAT_REQ)
                  break;
              if(!(tmp & STAT_REQ)) {
!               printf("sea_information_transfer: timeout waiting for
STAT_REQ\n");
                /* getchar(); */
              }
              if((tmp & REQ_MASK) != phase) {
***************
*** 2003,2008 ****
--- 2056,2066 ----
        printf("sea: unknown phase\n");
        } /* switch (phase) */
      } /* if (tmp & STAT_REQ) */
+     else {  /* if no STAT_REQ */
+       for(loop=0;loop<100;loop++)
+       if(STATUS & STAT_REQ)
+         break;
+     }
    } /* for (...) */
    /* if we get here we have got a timeout!  */
    printf("sea: Timeout in data transfer\n");


------------

Kent Palmkvist   	     	      Internet:   kentp@isy.liu.se
Dept. of Electrical Engineering
Linköping University            phone: +4613281347
58183 LINKÖPING                 fax:   +4613139282
Sweden