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

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