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

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