root/drivers/scsi/scsi_debug.c

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

DEFINITIONS

This source file includes following definitions.
  1. scsi_dump
  2. scsi_debug_queuecommand
  3. internal_done
  4. scsi_debug_command
  5. scsi_debug_intr_handle
  6. scsi_debug_detect
  7. scsi_debug_abort
  8. scsi_debug_biosparam
  9. scsi_debug_reset
  10. scsi_debug_info

   1 /* $Id: scsi_debug.c,v 1.1 1992/07/24 06:27:38 root Exp root $
   2  *  linux/kernel/scsi_debug.c
   3  *
   4  *  Copyright (C) 1992  Eric Youngdale
   5  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
   6  *  to make sure that we are not getting blocks mixed up, and panic if
   7  *  anything out of the ordinary is seen.
   8  */
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/sched.h>
  12 #include <linux/timer.h>
  13 #include <linux/head.h>
  14 #include <linux/types.h>
  15 #include <linux/string.h>
  16 #include <linux/genhd.h>
  17 #include <linux/fs.h>
  18 
  19 #include <asm/system.h>
  20 #include <asm/io.h>
  21 #include "../block/blk.h"
  22 #include "scsi.h"
  23 #include "hosts.h"
  24 
  25 #include "sd.h"
  26 
  27 /* A few options that we want selected */
  28 
  29 /* Do not attempt to use a timer to simulate a real disk with latency */
  30 /* Only use this in the actual kernel, not in the simulator. */
  31 #define IMMEDIATE
  32 
  33 /* Skip some consistency checking.  Good for benchmarking */
  34 #define SPEEDY
  35 
  36 /* Number of real scsi disks that will be detected ahead of time */
  37 static int NR_REAL=-1;
  38 
  39 #define NR_BLK_DEV      12
  40 #ifndef MAJOR_NR
  41 #define MAJOR_NR 8
  42 #endif
  43 #define START_PARTITION 4
  44 #define SCSI_DEBUG_TIMER 20
  45 /* Number of jiffies to wait before completing a command */
  46 #define DISK_SPEED     10
  47 #define CAPACITY (0x80000)
  48 
  49 static int starts[] = {4, 1000, 50000, CAPACITY, 0};
  50 static int npart = 0;
  51 
  52 #include "scsi_debug.h"
  53 #ifdef DEBUG
  54 #define DEB(x) x
  55 #else
  56 #define DEB(x)
  57 #endif
  58 
  59 #ifdef SPEEDY
  60 #define VERIFY1_DEBUG(RW) 1
  61 #define VERIFY_DEBUG(RW) 1
  62 #else
  63 
  64 #define VERIFY1_DEBUG(RW)                                               \
  65       if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");};                   \
  66       start = 0;                                                        \
  67       if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1];              \
  68       if (bh){                                                  \
  69         if (bh->b_size != 1024) panic ("Wrong bh size");        \
  70         if ((bh->b_blocknr << 1) + start != block)              \
  71           {  printk("Wrong bh block# %d %d ",bh->b_blocknr, block);  \
  72           panic ("Wrong bh block#");};  \
  73         if (bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\
  74       };
  75 
  76 #if 0
  77 /* This had been in the VERIFY_DEBUG macro, but it fails if there is already
  78    a disk on the system */
  79       if ((SCpnt->request.dev & 0xfff0) != ((target + NR_REAL) << 4) +(MAJOR_NR << 8)){ \
  80         printk("Dev #s %x %x ",SCpnt->request.dev, target);                     \
  81         panic ("Bad target");};                                         \
  82 
  83 #endif
  84 
  85 #define VERIFY_DEBUG(RW)                                                \
  86       if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");};      \
  87       start = 0;                                                        \
  88       if ((SCpnt->request.dev & 0xf) > npart) panic ("Bad partition");  \
  89       if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1];              \
  90       if (SCpnt->request.cmd != RW) panic ("Wrong  operation");         \
  91       if (SCpnt->request.sector + start != block) panic("Wrong block.");        \
  92       if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \
  93       if (SCpnt->request.bh){                                                   \
  94         if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
  95         if ((SCpnt->request.bh->b_blocknr << 1) + start != block)               \
  96           {  printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block);  \
  97           panic ("Wrong bh block#");};  \
  98         if (SCpnt->request.bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\
  99       };
 100 #endif
 101 
 102 static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, };
 103 extern void scsi_debug_interrupt();
 104 
 105 volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
 106 static volatile unsigned int timeout[SCSI_DEBUG_MAILBOXES] ={0,};
 107 
 108 static char sense_buffer[128] = {0,};
 109 
 110 static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
     /* [previous][next][first][last][top][bottom][index][help] */
 111   int i;
 112 #if 0
 113   unsigned char * pnt;
 114 #endif
 115   unsigned int * lpnt;
 116   struct scatterlist * sgpnt = NULL;
 117   printk("use_sg: %d",SCpnt->use_sg);
 118   if (SCpnt->use_sg){
 119     sgpnt = (struct scatterlist *) SCpnt->buffer;
 120     for(i=0; i<SCpnt->use_sg; i++) {
 121       lpnt = (int *) sgpnt[i].alt_address;
 122       printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
 123       if (lpnt) printk(" (Alt %x) ",lpnt[15]);
 124     };
 125   } else {
 126     printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
 127            SCpnt->bufflen);
 128     lpnt = (int *) SCpnt->request.buffer;
 129     if (lpnt) printk(" (Alt %x) ",lpnt[15]);
 130   };
 131   lpnt = (unsigned int *) SCpnt;
 132   for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
 133     if ((i & 7) == 0) printk("\n");
 134     printk("%x ",*lpnt++);
 135   };
 136   printk("\n");
 137   if (flag == 0) return;
 138   lpnt = (unsigned int *) sgpnt[0].alt_address;
 139   for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
 140     if ((i & 7) == 0) printk("\n");
 141     printk("%x ",*lpnt++);
 142   };
 143 #if 0
 144   printk("\n");
 145   lpnt = (unsigned int *) sgpnt[0].address;
 146   for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
 147     if ((i & 7) == 0) printk("\n");
 148     printk("%x ",*lpnt++);
 149   };
 150   printk("\n");
 151 #endif
 152   printk("DMA free %d sectors.\n", dma_free_sectors);
 153 }
 154 
 155 int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 156 {
 157     unchar *cmd = (unchar *) SCpnt->cmnd;
 158     struct partition * p;
 159     int block, start;
 160     struct buffer_head * bh = NULL;
 161     unsigned char * buff;
 162     int nbytes, sgcount;
 163     int scsi_debug_errsts;
 164     struct scatterlist * sgpnt;
 165     int target = SCpnt->target;
 166     int bufflen = SCpnt->request_bufflen;
 167     int i;
 168     sgcount = 0;
 169     sgpnt = NULL;
 170 
 171     DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;});
 172     
 173     buff = (unsigned char *) SCpnt->request_buffer;
 174 
 175     if(target>=1 || SCpnt->lun != 0) {
 176       SCpnt->result =  DID_NO_CONNECT << 16;
 177       done(SCpnt);
 178       return 0;
 179     };
 180     
 181     switch(*cmd){
 182     case REQUEST_SENSE:
 183       printk("Request sense...\n");
 184 #ifndef DEBUG
 185       { int i;
 186         printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
 187         for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
 188         printk("\n");
 189       };
 190 #endif
 191       memset(buff, 0, bufflen);
 192       memcpy(buff, sense_buffer, bufflen);
 193       memset(sense_buffer, 0, sizeof(sense_buffer));
 194       SCpnt->result = 0;
 195       done(SCpnt); 
 196       return 0;
 197     case ALLOW_MEDIUM_REMOVAL:
 198       if(cmd[4]) printk("Medium removal inhibited...");
 199       else printk("Medium removal enabled...");
 200       scsi_debug_errsts = 0;
 201       break;
 202     case INQUIRY:
 203       printk("Inquiry...(%x %d)\n", buff, bufflen);
 204       memset(buff, 0, bufflen);
 205       buff[0] = TYPE_DISK;
 206       buff[1] = 0x80;  /* Removable disk */
 207       buff[2] = 1;
 208       buff[4] = 33 - 5;
 209       memcpy(&buff[8],"Foo Inc",7);
 210       memcpy(&buff[16],"XYZZY",5);
 211       memcpy(&buff[32],"1",1);
 212       scsi_debug_errsts = 0;
 213       break;
 214     case TEST_UNIT_READY:
 215       printk("Test unit ready.\n");
 216       if (buff)
 217         memset(buff, 0, bufflen);
 218       scsi_debug_errsts = 0;
 219       break;
 220     case READ_CAPACITY:
 221       printk("Read Capacity\n");
 222       if(NR_REAL < 0) NR_REAL = (SCpnt->request.dev >> 4) & 0x0f;
 223       memset(buff, 0, bufflen);
 224       buff[0] = (CAPACITY >> 24);
 225       buff[1] = (CAPACITY >> 16) & 0xff;
 226       buff[2] = (CAPACITY >> 8) & 0xff;
 227       buff[3] = CAPACITY & 0xff;
 228       buff[6] = 2; /* 512 byte sectors */
 229       scsi_debug_errsts = 0;
 230       break;
 231     case READ_10:
 232     case READ_6:
 233 #ifdef DEBUG
 234       printk("Read...");
 235 #endif
 236       if ((*cmd) == READ_10)
 237         block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); 
 238       else 
 239         block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
 240       VERIFY_DEBUG(READ);
 241 #if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
 242       {
 243         int delay = SCSI_SETUP_LATENCY;
 244         double usec;
 245 
 246         usec = 0.0;
 247         usec = (SCpnt->request.nr_sectors << 9) * 1.0e6 / SCSI_DATARATE;
 248         delay += usec;
 249         if(delay) usleep(delay);
 250       };
 251 #endif
 252 
 253 #ifdef DEBUG
 254       printk("(r%d)",SCpnt->request.nr_sectors);
 255 #endif
 256       nbytes = bufflen;
 257       if(SCpnt->use_sg){
 258         sgcount = 0;
 259         sgpnt = (struct scatterlist *) buff;
 260         buff = sgpnt[sgcount].address;
 261         bufflen = sgpnt[sgcount].length;
 262         bh = SCpnt->request.bh;
 263       };
 264       scsi_debug_errsts = 0;
 265       do{
 266         VERIFY1_DEBUG(READ);
 267 /* For the speedy test, we do not even want to fill the buffer with anything */
 268 #ifndef SPEEDY
 269         memset(buff, 0, bufflen);
 270 #endif
 271 /* If this is block 0, then we want to read the partition table for this
 272    device.  Let's make one up */
 273         if(block == 0 && target == 0) {
 274           *((unsigned short *) (buff+510)) = 0xAA55;
 275           p = (struct partition* ) (buff + 0x1be);
 276           npart = 0;
 277           while(starts[npart+1]){
 278             p->start_sect = starts[npart];
 279             p->nr_sects = starts[npart+1] - starts [npart];
 280             p->sys_ind = 0x81;  /* Linux partition */
 281             p++;
 282             npart++;
 283           };
 284           scsi_debug_errsts = 0;
 285           break;
 286         };
 287 #ifdef DEBUG
 288         if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors,
 289                SCpnt->request.current_nr_sectors);
 290 #endif
 291 
 292 #if 0
 293         /* Simulate a disk change */
 294         if(block == 0xfff0) {
 295           sense_buffer[0] = 0x70;
 296           sense_buffer[2] = UNIT_ATTENTION;
 297           starts[0] += 10;
 298           starts[1] += 10;
 299           starts[2] += 10;
 300          
 301 #ifdef DEBUG
 302       { int i;
 303         printk("scsi_debug: Filling sense buffer:");
 304         for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
 305         printk("\n");
 306       };
 307 #endif
 308           scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 309           break;
 310         } /* End phony disk change code */
 311 #endif
 312 
 313 #ifndef SPEEDY
 314         memcpy(buff, &target, sizeof(target));
 315         memcpy(buff+sizeof(target), cmd, 24);
 316         memcpy(buff+60, &block, sizeof(block));
 317         memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd));
 318 #endif
 319         nbytes -= bufflen;
 320         if(SCpnt->use_sg){
 321 #ifndef SPEEDY
 322           memcpy(buff+128, bh, sizeof(struct buffer_head));
 323 #endif
 324           block += bufflen >> 9;
 325           bh = bh->b_reqnext;
 326           sgcount++;
 327           if (nbytes) {
 328             if(!bh) panic("Too few blocks for linked request.");
 329             buff = sgpnt[sgcount].address;
 330             bufflen = sgpnt[sgcount].length;
 331           };
 332         }
 333       } while(nbytes);
 334 
 335       SCpnt->result = 0;
 336       (done)(SCpnt);
 337       return;
 338 
 339       if (SCpnt->use_sg && !scsi_debug_errsts)
 340         if(bh) scsi_dump(SCpnt, 0);
 341       break;
 342     case WRITE_10:
 343     case WRITE_6:
 344 #ifdef DEBUG
 345       printk("Write\n");
 346 #endif
 347       if ((*cmd) == WRITE_10)
 348         block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); 
 349       else 
 350         block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
 351       VERIFY_DEBUG(WRITE);
 352 /*      printk("(w%d)",SCpnt->request.nr_sectors); */
 353       if (SCpnt->use_sg){
 354         if ((bufflen >> 9) != SCpnt->request.nr_sectors)
 355           panic ("Trying to write wrong number of blocks\n");
 356         sgpnt = (struct scatterlist *) buff;
 357         buff = sgpnt[sgcount].address;
 358       };
 359 #if 0
 360       if (block != *((unsigned long *) (buff+60))) {
 361         printk("%x %x :",block,  *((unsigned long *) (buff+60)));
 362         scsi_dump(SCpnt,1);
 363         panic("Bad block written.\n");
 364       };
 365 #endif
 366       scsi_debug_errsts = 0;
 367       break;
 368      default:
 369       printk("Unknown command %d\n",*cmd);
 370       SCpnt->result =  DID_NO_CONNECT << 16;
 371       done(SCpnt);
 372       return 0;
 373     };
 374 
 375     cli();
 376     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){
 377       if (SCint[i] == 0) break;
 378     };
 379 
 380     if (i >= SCSI_DEBUG_MAILBOXES || SCint[i] != 0) 
 381       panic("Unable to find empty SCSI_DEBUG command slot.\n");
 382 
 383     SCint[i] = SCpnt;
 384 
 385     if (done) {
 386         DEB(printk("scsi_debug_queuecommand: now waiting for interrupt "););
 387         if (do_done[i])
 388           printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");
 389         else
 390           do_done[i] = done;
 391     }
 392     else
 393       printk("scsi_debug_queuecommand: done cant be NULL\n");
 394 
 395 #ifdef IMMEDIATE
 396     SCpnt->result = scsi_debug_errsts;
 397     scsi_debug_intr_handle();  /* No timer - do this one right away */
 398 #else
 399     timeout[i] = jiffies+DISK_SPEED;
 400 
 401 /* If no timers active, then set this one */
 402     if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) {
 403       timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];
 404       timer_active |= 1 << SCSI_DEBUG_TIMER;
 405     };
 406 
 407     SCpnt->result = scsi_debug_errsts;
 408     sti();
 409 
 410 #if 0
 411     printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies);
 412 #endif
 413 #endif
 414 
 415     return 0;
 416 }
 417 
 418 volatile static int internal_done_flag = 0;
 419 volatile static int internal_done_errcode = 0;
 420 static void internal_done(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 421 {
 422     internal_done_errcode = SCpnt->result;
 423     ++internal_done_flag;
 424 }
 425 
 426 int scsi_debug_command(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 427 {
 428     DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n"));
 429     scsi_debug_queuecommand(SCpnt, internal_done);
 430 
 431     while (!internal_done_flag);
 432     internal_done_flag = 0;
 433     return internal_done_errcode;
 434 }
 435 
 436 /* A "high" level interrupt handler.  This should be called once per jiffy
 437  to simulate a regular scsi disk.  We use a timer to do this. */
 438 
 439 static void scsi_debug_intr_handle(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 440 {
 441     Scsi_Cmnd * SCtmp;
 442     int i, pending;
 443     void (*my_done)(Scsi_Cmnd *); 
 444    int to;
 445 
 446 #ifndef IMMEDIATE
 447     timer_table[SCSI_DEBUG_TIMER].expires = 0;
 448     timer_active &= ~(1 << SCSI_DEBUG_TIMER);
 449 #endif
 450 
 451   repeat:
 452     cli();
 453     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
 454       if (SCint[i] == 0) continue;
 455 #ifndef IMMEDIATE
 456       if (timeout[i] == 0) continue;
 457       if (timeout[i] <= jiffies) break;
 458 #else
 459       break;
 460 #endif
 461     };
 462 
 463     if(i == SCSI_DEBUG_MAILBOXES){
 464 #ifndef IMMEDIATE
 465       pending = INT_MAX;
 466       for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
 467         if (SCint[i] == 0) continue;
 468         if (timeout[i] == 0) continue;
 469         if (timeout[i] <= jiffies) {sti(); goto repeat;};
 470         if (timeout[i] > jiffies) {
 471           if (pending > timeout[i]) pending = timeout[i];
 472           continue;
 473         };
 474       };
 475       if (pending && pending != INT_MAX) {
 476         timer_table[SCSI_DEBUG_TIMER].expires = 
 477           (pending <= jiffies ? jiffies+1 : pending);
 478         timer_active |= 1 << SCSI_DEBUG_TIMER;
 479       };
 480       sti();
 481 #endif
 482       return;
 483     };
 484 
 485     if(i < SCSI_DEBUG_MAILBOXES){
 486       timeout[i] = 0;
 487       my_done = do_done[i];
 488       do_done[i] = NULL;
 489       to = timeout[i];
 490       timeout[i] = 0;
 491       SCtmp = (Scsi_Cmnd *) SCint[i];
 492       SCint[i] = NULL;
 493       sti();
 494 
 495       if (!my_done) {
 496         printk("scsi_debug_intr_handle: Unexpected interrupt\n"); 
 497         return;
 498       }
 499       
 500 #ifdef DEBUG
 501       printk("In intr_handle...");
 502       printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
 503       printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
 504 #endif
 505 
 506       my_done(SCtmp);
 507 #ifdef DEBUG
 508       printk("Called done.\n");
 509 #endif
 510     };
 511     goto repeat;
 512 }
 513 
 514 
 515 int scsi_debug_detect(Scsi_Host_Template * tpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 516 {
 517 #ifndef IMMEDIATE
 518     timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle;
 519     timer_table[SCSI_DEBUG_TIMER].expires = 0;
 520 #endif
 521     return 1;
 522 }
 523 
 524 int scsi_debug_abort(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 525 {
 526     int j;
 527     void (*my_done)(Scsi_Cmnd *);
 528     DEB(printk("scsi_debug_abort\n"));
 529     SCpnt->result = SCpnt->abort_reason << 16;
 530     for(j=0;j<SCSI_DEBUG_MAILBOXES; j++) {
 531       if(SCpnt == SCint[j]) {
 532         my_done = do_done[j];
 533         my_done(SCpnt);
 534         cli();
 535         timeout[j] = 0;
 536         SCint[j] = NULL;
 537         do_done[j] = NULL;
 538         sti();
 539       };
 540     };
 541     return 0;
 542 }
 543 
 544 int scsi_debug_biosparam(Disk * disk, int dev, int* info){
     /* [previous][next][first][last][top][bottom][index][help] */
 545   int size = disk->capacity;
 546   info[0] = 32;
 547   info[1] = 64;
 548   info[2] = (size + 2047) >> 11;
 549   if (info[2] >= 1024) info[2] = 1024;
 550   return 0;
 551 }
 552 
 553 int scsi_debug_reset(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 554 {
 555     int i;
 556     void (*my_done)(Scsi_Cmnd *);
 557     DEB(printk("scsi_debug_reset called\n"));
 558     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
 559       if (SCint[i] == NULL) continue;
 560       SCint[i]->result = DID_ABORT << 16;
 561       my_done = do_done[i];
 562       my_done(SCint[i]);
 563       cli();
 564       SCint[i] = NULL;
 565       do_done[i] = NULL;
 566       timeout[i] = 0;
 567       sti();
 568     };
 569     return 0;
 570 }
 571 
 572 const char *scsi_debug_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 573 {
 574     static char buffer[] = " ";                 /* looks nicer without anything here */
 575     return buffer;
 576 }
 577 
 578 

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