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

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