|
|
1.1 ! root 1: /* $Id: scsi_debug.c,v 1.1.1.1 1997/02/25 21:27:51 thomas Exp $ ! 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/module.h> ! 11: ! 12: #include <linux/kernel.h> ! 13: #include <linux/sched.h> ! 14: #include <linux/errno.h> ! 15: #include <linux/timer.h> ! 16: #include <linux/head.h> ! 17: #include <linux/types.h> ! 18: #include <linux/string.h> ! 19: #include <linux/genhd.h> ! 20: #include <linux/fs.h> ! 21: #include <linux/proc_fs.h> ! 22: ! 23: #include <asm/system.h> ! 24: #include <asm/io.h> ! 25: ! 26: #ifdef MODULE ! 27: #include <linux/module.h> ! 28: #endif ! 29: ! 30: #include <linux/blk.h> ! 31: #include "scsi.h" ! 32: #include "hosts.h" ! 33: ! 34: #include "sd.h" ! 35: ! 36: #include<linux/stat.h> ! 37: ! 38: struct proc_dir_entry proc_scsi_scsi_debug = { ! 39: PROC_SCSI_SCSI_DEBUG, 10, "scsi_debug", ! 40: S_IFDIR | S_IRUGO | S_IXUGO, 2 ! 41: }; ! 42: ! 43: ! 44: /* A few options that we want selected */ ! 45: ! 46: /* Do not attempt to use a timer to simulate a real disk with latency */ ! 47: /* Only use this in the actual kernel, not in the simulator. */ ! 48: #define IMMEDIATE ! 49: ! 50: /* Skip some consistency checking. Good for benchmarking */ ! 51: #define SPEEDY ! 52: ! 53: /* Number of real scsi disks that will be detected ahead of time */ ! 54: static int NR_REAL=-1; ! 55: ! 56: #define NR_BLK_DEV 12 ! 57: #ifndef MAJOR_NR ! 58: #define MAJOR_NR 8 ! 59: #endif ! 60: #define START_PARTITION 4 ! 61: #define SCSI_DEBUG_TIMER 20 ! 62: /* Number of jiffies to wait before completing a command */ ! 63: #define DISK_SPEED 10 ! 64: #define CAPACITY (0x80000) ! 65: ! 66: static int starts[] = {4, 1000, 50000, CAPACITY, 0}; ! 67: static int npart = 0; ! 68: ! 69: #include "scsi_debug.h" ! 70: #ifdef DEBUG ! 71: #define DEB(x) x ! 72: #else ! 73: #define DEB(x) ! 74: #endif ! 75: ! 76: #ifdef SPEEDY ! 77: #define VERIFY1_DEBUG(RW) 1 ! 78: #define VERIFY_DEBUG(RW) 1 ! 79: #else ! 80: ! 81: #define VERIFY1_DEBUG(RW) \ ! 82: if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \ ! 83: start = 0; \ ! 84: if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \ ! 85: if (bh){ \ ! 86: if (bh->b_size != 1024) panic ("Wrong bh size"); \ ! 87: if ((bh->b_blocknr << 1) + start != block) \ ! 88: { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \ ! 89: panic ("Wrong bh block#"); \ ! 90: }; \ ! 91: if (bh->b_dev != SCpnt->request.rq_dev) \ ! 92: panic ("Bad bh target"); \ ! 93: }; ! 94: ! 95: #define VERIFY_DEBUG(RW) \ ! 96: if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \ ! 97: start = 0; \ ! 98: if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition"); \ ! 99: if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \ ! 100: if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \ ! 101: if (SCpnt->request.sector + start != block) panic("Wrong block."); \ ! 102: if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \ ! 103: if (SCpnt->request.bh){ \ ! 104: if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \ ! 105: if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \ ! 106: { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \ ! 107: panic ("Wrong bh block#"); \ ! 108: }; \ ! 109: if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \ ! 110: panic ("Bad bh target");\ ! 111: }; ! 112: #endif ! 113: ! 114: static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, }; ! 115: extern void scsi_debug_interrupt(); ! 116: ! 117: volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,}; ! 118: static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,}; ! 119: static volatile unsigned int timeout[8] ={0,}; ! 120: ! 121: /* ! 122: * Semaphore used to simulate bus lockups. ! 123: */ ! 124: static int scsi_debug_lockup = 0; ! 125: ! 126: static char sense_buffer[128] = {0,}; ! 127: ! 128: static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){ ! 129: int i; ! 130: #if 0 ! 131: unsigned char * pnt; ! 132: #endif ! 133: unsigned int * lpnt; ! 134: struct scatterlist * sgpnt = NULL; ! 135: printk("use_sg: %d",SCpnt->use_sg); ! 136: if (SCpnt->use_sg){ ! 137: sgpnt = (struct scatterlist *) SCpnt->buffer; ! 138: for(i=0; i<SCpnt->use_sg; i++) { ! 139: lpnt = (int *) sgpnt[i].alt_address; ! 140: printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); ! 141: if (lpnt) printk(" (Alt %x) ",lpnt[15]); ! 142: }; ! 143: } else { ! 144: printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer, ! 145: SCpnt->bufflen); ! 146: lpnt = (int *) SCpnt->request.buffer; ! 147: if (lpnt) printk(" (Alt %x) ",lpnt[15]); ! 148: }; ! 149: lpnt = (unsigned int *) SCpnt; ! 150: for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) { ! 151: if ((i & 7) == 0) printk("\n"); ! 152: printk("%x ",*lpnt++); ! 153: }; ! 154: printk("\n"); ! 155: if (flag == 0) return; ! 156: lpnt = (unsigned int *) sgpnt[0].alt_address; ! 157: for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) { ! 158: if ((i & 7) == 0) printk("\n"); ! 159: printk("%x ",*lpnt++); ! 160: }; ! 161: #if 0 ! 162: printk("\n"); ! 163: lpnt = (unsigned int *) sgpnt[0].address; ! 164: for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) { ! 165: if ((i & 7) == 0) printk("\n"); ! 166: printk("%x ",*lpnt++); ! 167: }; ! 168: printk("\n"); ! 169: #endif ! 170: printk("DMA free %d sectors.\n", dma_free_sectors); ! 171: } ! 172: ! 173: int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) ! 174: { ! 175: unchar *cmd = (unchar *) SCpnt->cmnd; ! 176: struct partition * p; ! 177: int block, start; ! 178: struct buffer_head * bh = NULL; ! 179: unsigned char * buff; ! 180: int nbytes, sgcount; ! 181: int scsi_debug_errsts; ! 182: struct scatterlist * sgpnt; ! 183: int target = SCpnt->target; ! 184: int bufflen = SCpnt->request_bufflen; ! 185: unsigned long flags; ! 186: int i; ! 187: sgcount = 0; ! 188: sgpnt = NULL; ! 189: ! 190: DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;}); ! 191: ! 192: buff = (unsigned char *) SCpnt->request_buffer; ! 193: ! 194: if(target>=1 || SCpnt->lun != 0) { ! 195: SCpnt->result = DID_NO_CONNECT << 16; ! 196: done(SCpnt); ! 197: return 0; ! 198: }; ! 199: ! 200: if( SCrst[target] != 0 && !scsi_debug_lockup ) ! 201: { ! 202: SCrst[target] = 0; ! 203: memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); ! 204: SCpnt->sense_buffer[0] = 0x70; ! 205: SCpnt->sense_buffer[2] = UNIT_ATTENTION; ! 206: SCpnt->result = (CHECK_CONDITION << 1); ! 207: done(SCpnt); ! 208: } ! 209: switch(*cmd){ ! 210: case REQUEST_SENSE: ! 211: printk("Request sense...\n"); ! 212: #ifndef DEBUG ! 213: { ! 214: int i; ! 215: printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen); ! 216: for(i=0;i<12;i++) printk("%d ",sense_buffer[i]); ! 217: printk("\n"); ! 218: }; ! 219: #endif ! 220: memset(buff, 0, bufflen); ! 221: memcpy(buff, sense_buffer, bufflen); ! 222: memset(sense_buffer, 0, sizeof(sense_buffer)); ! 223: SCpnt->result = 0; ! 224: done(SCpnt); ! 225: return 0; ! 226: case ALLOW_MEDIUM_REMOVAL: ! 227: if(cmd[4]) printk("Medium removal inhibited..."); ! 228: else printk("Medium removal enabled..."); ! 229: scsi_debug_errsts = 0; ! 230: break; ! 231: case INQUIRY: ! 232: printk("Inquiry...(%x %d)\n", buff, bufflen); ! 233: memset(buff, 0, bufflen); ! 234: buff[0] = TYPE_DISK; ! 235: buff[1] = 0x80; /* Removable disk */ ! 236: buff[2] = 1; ! 237: buff[4] = 33 - 5; ! 238: memcpy(&buff[8],"Foo Inc",7); ! 239: memcpy(&buff[16],"XYZZY",5); ! 240: memcpy(&buff[32],"1",1); ! 241: scsi_debug_errsts = 0; ! 242: break; ! 243: case TEST_UNIT_READY: ! 244: printk("Test unit ready(%x %d)\n", buff, bufflen); ! 245: if (buff) ! 246: memset(buff, 0, bufflen); ! 247: scsi_debug_errsts = 0; ! 248: break; ! 249: case READ_CAPACITY: ! 250: printk("Read Capacity\n"); ! 251: if(NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f; ! 252: memset(buff, 0, bufflen); ! 253: buff[0] = (CAPACITY >> 24); ! 254: buff[1] = (CAPACITY >> 16) & 0xff; ! 255: buff[2] = (CAPACITY >> 8) & 0xff; ! 256: buff[3] = CAPACITY & 0xff; ! 257: buff[6] = 2; /* 512 byte sectors */ ! 258: scsi_debug_errsts = 0; ! 259: break; ! 260: case READ_10: ! 261: case READ_6: ! 262: #ifdef DEBUG ! 263: printk("Read..."); ! 264: #endif ! 265: if ((*cmd) == READ_10) ! 266: block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); ! 267: else ! 268: block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); ! 269: VERIFY_DEBUG(READ); ! 270: #if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE) ! 271: { ! 272: int delay = SCSI_SETUP_LATENCY; ! 273: double usec; ! 274: ! 275: usec = 0.0; ! 276: usec = (SCpnt->request.nr_sectors << 9) * 1.0e6 / SCSI_DATARATE; ! 277: delay += usec; ! 278: if(delay) usleep(delay); ! 279: }; ! 280: #endif ! 281: ! 282: #ifdef DEBUG ! 283: printk("(r%d)",SCpnt->request.nr_sectors); ! 284: #endif ! 285: nbytes = bufflen; ! 286: if(SCpnt->use_sg){ ! 287: sgcount = 0; ! 288: sgpnt = (struct scatterlist *) buff; ! 289: buff = sgpnt[sgcount].address; ! 290: bufflen = sgpnt[sgcount].length; ! 291: bh = SCpnt->request.bh; ! 292: }; ! 293: scsi_debug_errsts = 0; ! 294: do{ ! 295: VERIFY1_DEBUG(READ); ! 296: /* For the speedy test, we do not even want to fill the buffer with anything */ ! 297: #ifndef SPEEDY ! 298: memset(buff, 0, bufflen); ! 299: #endif ! 300: /* If this is block 0, then we want to read the partition table for this ! 301: * device. Let's make one up */ ! 302: if(block == 0 && target == 0) { ! 303: memset(buff, 0, bufflen); ! 304: *((unsigned short *) (buff+510)) = 0xAA55; ! 305: p = (struct partition* ) (buff + 0x1be); ! 306: npart = 0; ! 307: while(starts[npart+1]){ ! 308: p->start_sect = starts[npart]; ! 309: p->nr_sects = starts[npart+1] - starts [npart]; ! 310: p->sys_ind = 0x81; /* Linux partition */ ! 311: p++; ! 312: npart++; ! 313: }; ! 314: scsi_debug_errsts = 0; ! 315: break; ! 316: }; ! 317: #ifdef DEBUG ! 318: if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors, ! 319: SCpnt->request.current_nr_sectors); ! 320: #endif ! 321: ! 322: #if 0 ! 323: /* Simulate a disk change */ ! 324: if(block == 0xfff0) { ! 325: sense_buffer[0] = 0x70; ! 326: sense_buffer[2] = UNIT_ATTENTION; ! 327: starts[0] += 10; ! 328: starts[1] += 10; ! 329: starts[2] += 10; ! 330: ! 331: #ifdef DEBUG ! 332: { ! 333: int i; ! 334: printk("scsi_debug: Filling sense buffer:"); ! 335: for(i=0;i<12;i++) printk("%d ",sense_buffer[i]); ! 336: printk("\n"); ! 337: }; ! 338: #endif ! 339: scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); ! 340: break; ! 341: } /* End phony disk change code */ ! 342: #endif ! 343: ! 344: #ifndef SPEEDY ! 345: memcpy(buff, &target, sizeof(target)); ! 346: memcpy(buff+sizeof(target), cmd, 24); ! 347: memcpy(buff+60, &block, sizeof(block)); ! 348: memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd)); ! 349: #endif ! 350: nbytes -= bufflen; ! 351: if(SCpnt->use_sg){ ! 352: #ifndef SPEEDY ! 353: memcpy(buff+128, bh, sizeof(struct buffer_head)); ! 354: #endif ! 355: block += bufflen >> 9; ! 356: bh = bh->b_reqnext; ! 357: sgcount++; ! 358: if (nbytes) { ! 359: if(!bh) panic("Too few blocks for linked request."); ! 360: buff = sgpnt[sgcount].address; ! 361: bufflen = sgpnt[sgcount].length; ! 362: }; ! 363: } ! 364: } while(nbytes); ! 365: ! 366: SCpnt->result = 0; ! 367: (done)(SCpnt); ! 368: return; ! 369: ! 370: if (SCpnt->use_sg && !scsi_debug_errsts) ! 371: if(bh) scsi_dump(SCpnt, 0); ! 372: break; ! 373: case WRITE_10: ! 374: case WRITE_6: ! 375: #ifdef DEBUG ! 376: printk("Write\n"); ! 377: #endif ! 378: if ((*cmd) == WRITE_10) ! 379: block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); ! 380: else ! 381: block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); ! 382: VERIFY_DEBUG(WRITE); ! 383: /* printk("(w%d)",SCpnt->request.nr_sectors); */ ! 384: if (SCpnt->use_sg){ ! 385: if ((bufflen >> 9) != SCpnt->request.nr_sectors) ! 386: panic ("Trying to write wrong number of blocks\n"); ! 387: sgpnt = (struct scatterlist *) buff; ! 388: buff = sgpnt[sgcount].address; ! 389: }; ! 390: #if 0 ! 391: if (block != *((unsigned long *) (buff+60))) { ! 392: printk("%x %x :",block, *((unsigned long *) (buff+60))); ! 393: scsi_dump(SCpnt,1); ! 394: panic("Bad block written.\n"); ! 395: }; ! 396: #endif ! 397: scsi_debug_errsts = 0; ! 398: break; ! 399: default: ! 400: printk("Unknown command %d\n",*cmd); ! 401: SCpnt->result = DID_NO_CONNECT << 16; ! 402: done(SCpnt); ! 403: return 0; ! 404: }; ! 405: ! 406: save_flags(flags); ! 407: cli(); ! 408: for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){ ! 409: if (SCint[i] == 0) break; ! 410: }; ! 411: ! 412: if (i >= SCSI_DEBUG_MAILBOXES || SCint[i] != 0) ! 413: panic("Unable to find empty SCSI_DEBUG command slot.\n"); ! 414: ! 415: SCint[i] = SCpnt; ! 416: ! 417: if (done) { ! 418: DEB(printk("scsi_debug_queuecommand: now waiting for interrupt ");); ! 419: if (do_done[i]) ! 420: printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n"); ! 421: else ! 422: do_done[i] = done; ! 423: } ! 424: else ! 425: printk("scsi_debug_queuecommand: done cant be NULL\n"); ! 426: ! 427: #ifdef IMMEDIATE ! 428: if( !scsi_debug_lockup ) ! 429: { ! 430: SCpnt->result = scsi_debug_errsts; ! 431: scsi_debug_intr_handle(); /* No timer - do this one right away */ ! 432: } ! 433: restore_flags(flags); ! 434: #else ! 435: timeout[i] = jiffies+DISK_SPEED; ! 436: ! 437: /* If no timers active, then set this one */ ! 438: if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) { ! 439: timer_table[SCSI_DEBUG_TIMER].expires = timeout[i]; ! 440: timer_active |= 1 << SCSI_DEBUG_TIMER; ! 441: }; ! 442: ! 443: SCpnt->result = scsi_debug_errsts; ! 444: restore_flags(flags); ! 445: ! 446: #if 0 ! 447: printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies); ! 448: #endif ! 449: #endif ! 450: ! 451: return 0; ! 452: } ! 453: ! 454: volatile static int internal_done_flag = 0; ! 455: volatile static int internal_done_errcode = 0; ! 456: static void internal_done(Scsi_Cmnd * SCpnt) ! 457: { ! 458: internal_done_errcode = SCpnt->result; ! 459: ++internal_done_flag; ! 460: } ! 461: ! 462: int scsi_debug_command(Scsi_Cmnd * SCpnt) ! 463: { ! 464: DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n")); ! 465: scsi_debug_queuecommand(SCpnt, internal_done); ! 466: ! 467: while (!internal_done_flag); ! 468: internal_done_flag = 0; ! 469: return internal_done_errcode; ! 470: } ! 471: ! 472: /* A "high" level interrupt handler. This should be called once per jiffy ! 473: * to simulate a regular scsi disk. We use a timer to do this. */ ! 474: ! 475: static void scsi_debug_intr_handle(void) ! 476: { ! 477: Scsi_Cmnd * SCtmp; ! 478: int i, pending; ! 479: void (*my_done)(Scsi_Cmnd *); ! 480: unsigned long flags; ! 481: int to; ! 482: ! 483: #ifndef IMMEDIATE ! 484: timer_table[SCSI_DEBUG_TIMER].expires = 0; ! 485: timer_active &= ~(1 << SCSI_DEBUG_TIMER); ! 486: #endif ! 487: ! 488: repeat: ! 489: save_flags(flags); ! 490: cli(); ! 491: for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) { ! 492: if (SCint[i] == 0) continue; ! 493: #ifndef IMMEDIATE ! 494: if (timeout[i] == 0) continue; ! 495: if (timeout[i] <= jiffies) break; ! 496: #else ! 497: break; ! 498: #endif ! 499: }; ! 500: ! 501: if(i == SCSI_DEBUG_MAILBOXES){ ! 502: #ifndef IMMEDIATE ! 503: pending = INT_MAX; ! 504: for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) { ! 505: if (SCint[i] == 0) continue; ! 506: if (timeout[i] == 0) continue; ! 507: if (timeout[i] <= jiffies) {restore_flags(flags); goto repeat;}; ! 508: if (timeout[i] > jiffies) { ! 509: if (pending > timeout[i]) pending = timeout[i]; ! 510: continue; ! 511: }; ! 512: }; ! 513: if (pending && pending != INT_MAX) { ! 514: timer_table[SCSI_DEBUG_TIMER].expires = ! 515: (pending <= jiffies ? jiffies+1 : pending); ! 516: timer_active |= 1 << SCSI_DEBUG_TIMER; ! 517: }; ! 518: restore_flags(flags); ! 519: #endif ! 520: return; ! 521: }; ! 522: ! 523: if(i < SCSI_DEBUG_MAILBOXES){ ! 524: timeout[i] = 0; ! 525: my_done = do_done[i]; ! 526: do_done[i] = NULL; ! 527: to = timeout[i]; ! 528: timeout[i] = 0; ! 529: SCtmp = (Scsi_Cmnd *) SCint[i]; ! 530: SCint[i] = NULL; ! 531: restore_flags(flags); ! 532: ! 533: if (!my_done) { ! 534: printk("scsi_debug_intr_handle: Unexpected interrupt\n"); ! 535: return; ! 536: } ! 537: ! 538: #ifdef DEBUG ! 539: printk("In intr_handle..."); ! 540: printk("...done %d %x %d %d\n",i , my_done, to, jiffies); ! 541: printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done); ! 542: #endif ! 543: ! 544: my_done(SCtmp); ! 545: #ifdef DEBUG ! 546: printk("Called done.\n"); ! 547: #endif ! 548: }; ! 549: goto repeat; ! 550: } ! 551: ! 552: ! 553: int scsi_debug_detect(Scsi_Host_Template * tpnt) ! 554: { ! 555: tpnt->proc_dir = &proc_scsi_scsi_debug; ! 556: #ifndef IMMEDIATE ! 557: timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle; ! 558: timer_table[SCSI_DEBUG_TIMER].expires = 0; ! 559: #endif ! 560: return 1; ! 561: } ! 562: ! 563: int scsi_debug_abort(Scsi_Cmnd * SCpnt) ! 564: { ! 565: int j; ! 566: void (*my_done)(Scsi_Cmnd *); ! 567: unsigned long flags; ! 568: ! 569: DEB(printk("scsi_debug_abort\n")); ! 570: #if 0 ! 571: SCpnt->result = SCpnt->abort_reason << 16; ! 572: for(j=0;j<SCSI_DEBUG_MAILBOXES; j++) { ! 573: if(SCpnt == SCint[j]) { ! 574: my_done = do_done[j]; ! 575: my_done(SCpnt); ! 576: save_flags(flags); ! 577: cli(); ! 578: timeout[j] = 0; ! 579: SCint[j] = NULL; ! 580: do_done[j] = NULL; ! 581: restore_flags(flags); ! 582: }; ! 583: }; ! 584: #endif ! 585: return SCSI_ABORT_SNOOZE; ! 586: } ! 587: ! 588: int scsi_debug_biosparam(Disk * disk, kdev_t dev, int* info){ ! 589: int size = disk->capacity; ! 590: info[0] = 32; ! 591: info[1] = 64; ! 592: info[2] = (size + 2047) >> 11; ! 593: if (info[2] >= 1024) info[2] = 1024; ! 594: return 0; ! 595: } ! 596: ! 597: int scsi_debug_reset(Scsi_Cmnd * SCpnt) ! 598: { ! 599: int i; ! 600: unsigned long flags; ! 601: ! 602: void (*my_done)(Scsi_Cmnd *); ! 603: printk("Bus unlocked by reset(%d)\n", SCpnt->host->suggest_bus_reset); ! 604: scsi_debug_lockup = 0; ! 605: DEB(printk("scsi_debug_reset called\n")); ! 606: for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) { ! 607: if (SCint[i] == NULL) continue; ! 608: SCint[i]->result = DID_RESET << 16; ! 609: my_done = do_done[i]; ! 610: my_done(SCint[i]); ! 611: save_flags(flags); ! 612: cli(); ! 613: SCint[i] = NULL; ! 614: do_done[i] = NULL; ! 615: timeout[i] = 0; ! 616: restore_flags(flags); ! 617: } ! 618: return SCSI_RESET_SUCCESS; ! 619: } ! 620: ! 621: const char *scsi_debug_info(void) ! 622: { ! 623: static char buffer[] = " "; /* looks nicer without anything here */ ! 624: return buffer; ! 625: } ! 626: ! 627: /* scsi_debug_proc_info ! 628: * Used if the driver currently has no own support for /proc/scsi ! 629: */ ! 630: int scsi_debug_proc_info(char *buffer, char **start, off_t offset, ! 631: int length, int inode, int inout) ! 632: { ! 633: int len, pos, begin; ! 634: int orig_length; ! 635: ! 636: if(inout == 1) ! 637: { ! 638: /* First check for the Signature */ ! 639: if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) { ! 640: buffer += 11; ! 641: length -= 11; ! 642: /* ! 643: * OK, we are getting some kind of command. Figure out ! 644: * what we are supposed to do here. Simulate bus lockups ! 645: * to test our reset capability. ! 646: */ ! 647: if( length == 6 && strncmp(buffer, "lockup", length) == 0 ) ! 648: { ! 649: scsi_debug_lockup = 1; ! 650: return length; ! 651: } ! 652: ! 653: if( length == 6 && strncmp(buffer, "unlock", length) == 0 ) ! 654: { ! 655: scsi_debug_lockup = 0; ! 656: return length; ! 657: } ! 658: ! 659: printk("Unknown command:%s\n", buffer); ! 660: } else ! 661: printk("Wrong Signature:%10s\n", (char *) ((ulong)buffer-11)); ! 662: ! 663: return -EINVAL; ! 664: ! 665: } ! 666: ! 667: begin = 0; ! 668: pos = len = sprintf(buffer, ! 669: "This driver is not a real scsi driver, but it plays one on TV.\n" ! 670: "It is very handy for debugging specific problems because you\n" ! 671: "can simulate a variety of error conditions\n"); ! 672: if(pos < offset) ! 673: { ! 674: len = 0; ! 675: begin = pos; ! 676: } ! 677: ! 678: *start = buffer + (offset - begin); /* Start of wanted data */ ! 679: len -= (offset - begin); ! 680: if(len > length) ! 681: len = length; ! 682: ! 683: return(len); ! 684: } ! 685: ! 686: #ifdef MODULE ! 687: /* Eventually this will go into an include file, but this will be later */ ! 688: Scsi_Host_Template driver_template = SCSI_DEBUG; ! 689: ! 690: #include "scsi_module.c" ! 691: #endif ! 692: ! 693: /* ! 694: * Overrides for Emacs so that we almost follow Linus's tabbing style. ! 695: * Emacs will notice this stuff at the end of the file and automatically ! 696: * adjust the settings for this buffer only. This must remain at the end ! 697: * of the file. ! 698: * --------------------------------------------------------------------------- ! 699: * Local variables: ! 700: * c-indent-level: 4 ! 701: * c-brace-imaginary-offset: 0 ! 702: * c-brace-offset: -4 ! 703: * c-argdecl-indent: 4 ! 704: * c-label-offset: -4 ! 705: * c-continued-statement-offset: 4 ! 706: * c-continued-brace-offset: 0 ! 707: * indent-tabs-mode: nil ! 708: * tab-width: 8 ! 709: * End: ! 710: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.