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

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