root/drivers/scsi/ppa.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. out_p
  2. in_p
  3. ppa_d_pulse
  4. ppa_disconnect
  5. ppa_c_pulse
  6. ppa_connect
  7. ppa_do_reset
  8. ppa_select
  9. ppa_wait
  10. ppa_init
  11. ppa_start
  12. ppa_completion
  13. ppa_command
  14. ppa_queuecommand
  15. ppa_detect
  16. ppa_biosparam
  17. ppa_abort
  18. ppa_reset
  19. ppa_info
  20. ppa_setup

   1 /*      ppa.c   --  low level driver for the IOMEGA PPA3 
   2                     parallel port SCSI host adapter.
   3 
   4         (The PPA3 is the embedded controller in the ZIP drive.)
   5 
   6         (c) 1995,1996 Grant R. Guenther, grant@torque.net,
   7                       under the terms of the GNU Public License.
   8 
   9         THIS IS BETA SOFTWARE - PLEASE TAKE ALL NECESSARY PRECAUTIONS
  10 
  11 */
  12 
  13 /*      This driver was developed without the benefit of any technical
  14         specifications for the interface.  Instead, a modified version of
  15         DOSemu was used to monitor the protocol used by the DOS driver
  16         for this adapter.  I have no idea how my programming model relates
  17         to IOMEGA's design.
  18 
  19         IOMEGA's driver does not generate linked commands.  I've never
  20         observed a SCSI message byte in the protocol transactions, so
  21         I am assuming that as long as linked commands are not used
  22         we won't see any.  
  23 
  24         So far, this driver has been tested with the embedded PPA3 in the
  25         ZIP drive, only.   It can detect and adapt to 4- and 8-bit parallel
  26         ports, but there is currently no support for EPP or ECP ports, as
  27         I have been unable to make the DOS drivers work in these modes on
  28         my test rig.
  29 
  30         For more information, see the file drivers/scsi/README.ppa.
  31 
  32 */
  33 
  34 #define   PPA_VERSION   "0.20"
  35 
  36 /* Change these variables here or with insmod or with a LILO or LOADLIN
  37    command line argument
  38 */
  39 
  40 static int      ppa_base       = 0x378;  /* parallel port address    */
  41 static int      ppa_speed_high = 1;      /* port delay in data phase */
  42 static int      ppa_speed_low  = 6;      /* port delay otherwise     */
  43 static int      ppa_call_sched = 1;      /* give up the CPU ?        */
  44 static int      ppa_nybble     = 0;      /* don't force nybble mode  */
  45 
  46 
  47 #define   PPA_CAN_QUEUE         1       /* use "queueing" interface */
  48 #define   PPA_SELECT_TMO        5000    /* how long to wait for target ? */
  49 #define   PPA_SPIN_TMO          5000000 /* ppa_wait loop limiter */
  50 #define   PPA_SECTOR_SIZE       512     /* for a performance hack only */
  51 
  52 #include  <unistd.h>
  53 #include  <linux/module.h>
  54 #include  <linux/kernel.h>
  55 #include  <linux/ioport.h>
  56 #include  <linux/delay.h>
  57 #include  <linux/blk.h>
  58 #include  <linux/proc_fs.h>
  59 #include  <linux/stat.h>
  60 #include  <asm/io.h>
  61 #include  "sd.h"
  62 #include  "hosts.h"
  63 #include  "ppa.h"
  64 
  65 struct proc_dir_entry proc_scsi_ppa = 
  66                 { PROC_SCSI_PPA, 3, "ppa", S_IFDIR|S_IRUGO|S_IXUGO, 2 };
  67 
  68 static int              ppa_abort_flag = 0;
  69 static int              ppa_error_code = DID_OK;
  70 static char             ppa_info_string[132];
  71 static Scsi_Cmnd        *ppa_current = 0;
  72 static void             (*ppa_done) (Scsi_Cmnd *);
  73 static int              ppa_busy = 0;
  74 static int              ppa_port_delay;
  75 
  76 
  77 void    out_p( short port, char byte)
     /* [previous][next][first][last][top][bottom][index][help] */
  78 
  79 {       outb(byte,ppa_base+port);
  80         udelay(ppa_port_delay);
  81 }
  82 
  83 char    in_p( short port)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 
  85 {       return inb(ppa_base+port);
  86         udelay(ppa_port_delay);
  87 }
  88 
  89 void    ppa_d_pulse( char b )
     /* [previous][next][first][last][top][bottom][index][help] */
  90 
  91 {       out_p(0,b);
  92         out_p(2,0xc); out_p(2,0xe); out_p(2,0xc); out_p(2,0x4); out_p(2,0xc);
  93 }
  94 
  95 void    ppa_disconnect( void )
     /* [previous][next][first][last][top][bottom][index][help] */
  96 
  97 {       ppa_d_pulse(0);
  98         ppa_d_pulse(0x3c);
  99         ppa_d_pulse(0x20);
 100         ppa_d_pulse(0xf);
 101 }
 102 
 103 void    ppa_c_pulse( char b )
     /* [previous][next][first][last][top][bottom][index][help] */
 104 
 105 {       out_p(0,b);
 106         out_p(2,0x4); out_p(2,0x6); out_p(2,0x4); out_p(2,0xc);
 107 }
 108 
 109 void    ppa_connect( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 110 
 111 {       ppa_c_pulse(0);
 112         ppa_c_pulse(0x3c);
 113         ppa_c_pulse(0x20);
 114         ppa_c_pulse(0x8f);
 115 }
 116 
 117 void    ppa_do_reset( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 118 
 119 {       out_p(2,0);             /* This is really just a guess */
 120         udelay(100);
 121 }
 122 
 123 char    ppa_select( int  initiator, int target )
     /* [previous][next][first][last][top][bottom][index][help] */
 124 
 125 {       char    r;
 126         int     k;
 127 
 128         r = in_p(1);
 129         out_p(0,(1<<target)); out_p(2,0xe); out_p(2,0xc);
 130         out_p(0,(1<<initiator)); out_p(2,0x8);
 131 
 132         k = 0;
 133         while ( !(r = (in_p(1) & 0xf0)) && (k++ < PPA_SELECT_TMO)) barrier();
 134         return r;
 135 }
 136 
 137 char    ppa_wait( void ) 
     /* [previous][next][first][last][top][bottom][index][help] */
 138 
 139 /*      Wait for the high bit to be set.
 140 
 141         In principle, this could be tied to an interrupt, but the adapter
 142         doesn't appear to be designed to support interrupts.  We spin on
 143         the 0x80 ready bit.  If ppa_call_sched is 1, we call the scheduler 
 144         to allow other processes to run while we are waiting, just like
 145         the lp driver does in polling mode.  The performance hit is
 146         significant, so this behaviour is configurable.
 147 
 148 */
 149 
 150 {       int     k;
 151         char    r;
 152 
 153         ppa_error_code = DID_OK;
 154         k = 0;
 155         while (!((r = in_p(1)) & 0x80) 
 156                 && (k++ < PPA_SPIN_TMO) && !ppa_abort_flag  )
 157                         if (need_resched && ppa_call_sched) schedule();
 158         if (ppa_abort_flag) {
 159                 if (ppa_abort_flag == 1) ppa_error_code = DID_ABORT;
 160                 else {  ppa_do_reset();
 161                         ppa_error_code = DID_RESET;
 162                 }
 163                 ppa_disconnect();
 164                 return 0;
 165         }
 166         if (k >= PPA_SPIN_TMO) { 
 167                 ppa_error_code = DID_TIME_OUT;
 168                 ppa_disconnect();
 169                 return 0;               /* command timed out */
 170         }
 171         return (r & 0xf0);
 172 }
 173 
 174 int     ppa_init( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 175 
 176 /* This is based on a trace of what the Iomega DOS 'guest' driver does.
 177    I've tried several different kinds of parallel ports with guest and
 178    coded this to react in the same ways that it does.
 179 
 180    The return value from this function is just a hint about where the
 181    handshaking failed.
 182 
 183 */
 184 
 185 {       char    r, s;
 186 
 187         out_p(0,0xaa); 
 188         if (in_p(0) != (char) 0xaa) return 1; 
 189         ppa_disconnect();
 190         ppa_connect();
 191         out_p(2,0x6); 
 192         if ((in_p(1) & 0xf0) != 0xf0) return 2; 
 193         out_p(2,0x4);
 194         if ((in_p(1) & 0xf0) != 0x80) return 3; 
 195         ppa_disconnect();
 196         s = in_p(2);
 197         out_p(2,0xec);
 198         out_p(0,0x55); 
 199         r = in_p(0);    
 200         if (r != (char) 0xff) { 
 201                 ppa_nybble = 1;
 202                 if (r != (char) 0x55) return 4; 
 203                 out_p(0,0xaa); if (in_p(0) != (char) 0xaa) return 5; 
 204         }
 205         out_p(2,s);
 206         ppa_connect();
 207         out_p(0,0x40); out_p(2,0x8); out_p(2,0xc);
 208         ppa_disconnect();
 209 
 210         return 0;
 211 }
 212 
 213 int     ppa_start( Scsi_Cmnd * cmd )
     /* [previous][next][first][last][top][bottom][index][help] */
 214 
 215 {       int     k;
 216 
 217         ppa_error_code = DID_OK;
 218         ppa_abort_flag = 0;
 219 
 220         if (cmd->target == PPA_INITIATOR) {
 221                 ppa_error_code = DID_BAD_TARGET;
 222                 return 0;
 223         }
 224         ppa_connect();
 225         if (!ppa_select(PPA_INITIATOR,cmd->target)) {
 226                 ppa_disconnect();
 227                 ppa_error_code = DID_NO_CONNECT;
 228                 return 0;
 229         }
 230         out_p(2,0xc);
 231 
 232         for (k=0; k < cmd->cmd_len; k++) {        /* send the command */
 233                 if (!ppa_wait()) return 0;
 234                 out_p(0,cmd->cmnd[k]);
 235                 out_p(2,0xe);
 236                 out_p(2,0xc);
 237         }
 238 
 239 #ifdef PPA_DEBUG
 240         printk("PPA: command out: ");
 241         for (k=0; k < cmd->cmd_len; k++)
 242                 printk("%3x",(cmd->cmnd[k]) & 0xff );
 243         printk("\n");
 244 #endif
 245 
 246         return 1;
 247 }
 248 
 249 int     ppa_completion( Scsi_Cmnd * cmd )
     /* [previous][next][first][last][top][bottom][index][help] */
 250 
 251 /* The bulk flag enables some optimisations in the data transfer loops,
 252    it should be true for any command that transfers data in integral
 253    numbers of sectors.
 254 
 255    The driver appears to remain stable if we speed up the parallel port
 256    i/o in this function, but not elsewhere.
 257 */
 258 
 259 {       char    r, l, h, v;
 260         int     dir, cnt, blen, fast, bulk;
 261         char    *buffer;
 262 
 263 #ifdef PPA_DEBUG
 264         int     k;
 265 #endif
 266 
 267         if (!(r = ppa_wait())) return 0;
 268         v = cmd->cmnd[0];
 269         bulk = ((v==READ_6)||(v==READ_10)||(v==WRITE_6)||(v==WRITE_10));
 270         buffer = cmd->request_buffer;
 271         blen = cmd->request_bufflen;
 272         cnt = 0;  dir = 0;
 273         if (r == (char) 0xc0) dir = 1;  /* d0 = read c0 = write f0 = status */
 274 
 275         ppa_port_delay = ppa_speed_high;
 276 
 277         while (r != (char) 0xf0) {
 278                 if (((r & 0xc0) != 0xc0 ) || (cnt >= blen)) {
 279                         ppa_disconnect();
 280                         ppa_error_code = DID_ERROR;
 281                         return 0;
 282                 }
 283                 fast = bulk && ((blen - cnt) >= PPA_SECTOR_SIZE);
 284                 if (dir) do {
 285                         out_p(0,buffer[cnt++]);
 286                         out_p(2,0xe); out_p(2,0xc);
 287                         if (!fast) break;
 288                 } while (cnt % PPA_SECTOR_SIZE);
 289                 else {  
 290                         if (ppa_nybble) do {
 291                                 out_p(2,0x4); h = in_p(1); 
 292                                 out_p(2,0x6); l = in_p(1);
 293                                 v = ((l >> 4) & 0x0f) + (h & 0xf0);
 294                                 buffer[cnt++] = v;
 295                                 if (!fast) break;
 296                         } while (cnt % PPA_SECTOR_SIZE);
 297                         else do {
 298                                 out_p(2,0x25); v = in_p(0); out_p(2,0x27);
 299                                 buffer[cnt++] = v;
 300                                 if (!fast) break;
 301                         } while (cnt % PPA_SECTOR_SIZE);
 302                         if (!ppa_nybble) {
 303                                 out_p(2,0x5); out_p(2,0x4);
 304                         }
 305                         out_p(2,0xc);
 306                 }
 307                 if (!(r = ppa_wait())) return 0;
 308         }
 309 
 310         ppa_port_delay = ppa_speed_low;
 311 
 312         out_p(2,0x4);            /* now read status byte */
 313         h = in_p(1);
 314         out_p(2,0x6);
 315         l = in_p(1);
 316         out_p(2,0xc);
 317         r = ((l >> 4) & 0x0f) + (h & 0xf0);
 318 
 319         out_p(2,0xe); out_p(2,0xc);
 320         ppa_disconnect();
 321 
 322 #ifdef PPA_DEBUG
 323         printk("PPA: status: %x, data[%d]: ",r & STATUS_MASK,cnt);
 324         if (cnt > 12) cnt = 12;
 325         for (k=0; k < cnt; k++)
 326            printk("%3x",buffer[k] & 0xff );
 327         printk("\n");   
 328 #endif
 329 
 330         return (r & STATUS_MASK);
 331 }
 332 
 333 int     ppa_command( Scsi_Cmnd * cmd )
     /* [previous][next][first][last][top][bottom][index][help] */
 334 
 335 {       int     s;
 336 
 337         s = 0;
 338         if (ppa_start(cmd))
 339            if (ppa_wait()) 
 340                s = ppa_completion(cmd);
 341         return s + (ppa_error_code << 16);
 342 }
 343 
 344 int     ppa_queuecommand( Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 345 
 346 /* This is not really a queued interface at all, but apparently there may
 347    be some bugs in the mid-level support for the non-queued interface.
 348    This function is re-entrant, but only to one level.
 349 */
 350 
 351 {       int     s;
 352 
 353         ppa_current = cmd; ppa_done = done;
 354         if (ppa_busy) return 0;
 355         ppa_busy = 1;
 356         while (ppa_current) {
 357                 cmd = ppa_current;  done = ppa_done;
 358                 s = 0;
 359                 if (ppa_start(cmd))
 360                     if (ppa_wait())
 361                         s = ppa_completion(cmd);
 362                 cmd->result = s + (ppa_error_code << 16);
 363                 ppa_current = 0;
 364                 done(cmd);              /* can reenter this function */
 365         }
 366         ppa_busy = 0;
 367         return 0;
 368 }
 369 
 370 int     ppa_detect( Scsi_Host_Template * host )
     /* [previous][next][first][last][top][bottom][index][help] */
 371 
 372 {       struct  Scsi_Host       *hreg;
 373         int     rs;
 374 
 375         /* can we have the ports ? */
 376 
 377         if (check_region(ppa_base,3)) {
 378                 printk("PPA: ports at 0x%3x are not available\n",ppa_base);
 379                 return 0;
 380         }
 381 
 382         /* attempt to initialise the controller */
 383 
 384         ppa_port_delay = ppa_speed_low;
 385 
 386         rs = ppa_init();
 387         if (rs) {
 388             printk("PPA: unable to initialise controller at 0x%x, error %d\n",
 389                    ppa_base,rs);
 390             return 0;
 391         }
 392 
 393         /* now the glue ... */
 394 
 395         host->proc_dir = &proc_scsi_ppa;
 396 
 397         request_region(ppa_base,3,"ppa");
 398 
 399         host->can_queue = PPA_CAN_QUEUE;
 400 
 401         hreg = scsi_register(host,0);
 402         hreg->io_port = ppa_base;
 403         hreg->n_io_port = 3;
 404         hreg->dma_channel = -1;
 405 
 406         sprintf(ppa_info_string,
 407                 "PPA driver version %s using %d-bit mode on port 0x%x.",
 408                 PPA_VERSION,8-ppa_nybble*4,ppa_base);
 409         host->name = ppa_info_string;
 410 
 411         return 1;       /* 1 host detected */
 412 }
 413 
 414 int     ppa_biosparam( Disk * disk, kdev_t dev, int ip[])
     /* [previous][next][first][last][top][bottom][index][help] */
 415 
 416 /*  Apparently the the disk->capacity attribute is off by 1 sector 
 417     for all disk drives.  We add the one here, but it should really
 418     be done in sd.c.  Even if it gets fixed there, this will still
 419     work.
 420 */
 421 
 422 {       ip[0] = 0x40;
 423         ip[1] = 0x20;
 424         ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
 425         if (ip[2] > 1024) {
 426                 ip[0] = 0xff;
 427                 ip[1] = 0x3f;
 428                 ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
 429                 if (ip[2] > 1023)
 430                         ip[2] = 1023;
 431         }
 432         return 0;
 433 }
 434 
 435 int     ppa_abort( Scsi_Cmnd * cmd )
     /* [previous][next][first][last][top][bottom][index][help] */
 436 
 437 {       ppa_abort_flag = 1;
 438         return SCSI_ABORT_SNOOZE;
 439 }
 440 
 441 int     ppa_reset( Scsi_Cmnd * cmd )
     /* [previous][next][first][last][top][bottom][index][help] */
 442 
 443 {       ppa_abort_flag = 2;
 444         return SCSI_RESET_PUNT;
 445 }
 446 
 447 const char      *ppa_info( struct Scsi_Host * host )
     /* [previous][next][first][last][top][bottom][index][help] */
 448 
 449 {       return ppa_info_string;
 450 }
 451 
 452 #ifndef MODULE
 453 
 454 /* Command line parameters (for built-in driver):
 455 
 456    Syntax:  ppa=base[,speed_high[,speed_low[,call_sched[,nybble]]]]
 457 
 458    For example:  ppa=0x378   or   ppa=0x378,0,3
 459 
 460 */
 461 
 462 void    ppa_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 463 
 464 {       if (ints[0] > 0) ppa_base = ints[1];
 465         if (ints[0] > 1) ppa_speed_high = ints[2];
 466         if (ints[0] > 2) ppa_speed_low = ints[3];
 467         if (ints[0] > 3) ppa_call_sched = ints[4];
 468         if (ints[0] > 4) ppa_nybble = ints[5];
 469 }
 470 
 471 #else
 472 
 473 Scsi_Host_Template      driver_template = PPA;
 474 
 475 #include  "scsi_module.c"
 476 
 477 #endif
 478 
 479 /* end of ppa.c */

/* [previous][next][first][last][top][bottom][index][help] */