📄 scsi_debug.c
字号:
/* $Id: scsi_debug.c,v 1.1 1992/07/24 06:27:38 root Exp root $ * linux/kernel/scsi_debug.c * * Copyright (C) 1992 Eric Youngdale * Simulate a host adapter with 2 disks attached. Do a lot of checking * to make sure that we are not getting blocks mixed up, and panic if * anything out of the ordinary is seen. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/types.h>#include <linux/string.h>#include <linux/genhd.h>#include <linux/fs.h>#include <linux/proc_fs.h>#include <asm/system.h>#include <asm/io.h>#include <linux/blk.h>#include "scsi.h"#include "hosts.h"#include "sd.h"#include<linux/stat.h>/* A few options that we want selected */#define NR_HOSTS_PRESENT 1#define NR_FAKE_DISKS 3#define N_HEAD 255#define N_SECTOR 63#define N_CYLINDER 524#define DISK_READONLY(TGT) (0)#define DISK_REMOVEABLE(TGT) (1)#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK);/* Do not attempt to use a timer to simulate a real disk with latency *//* Only use this in the actual kernel, not in the simulator. */#define IMMEDIATE/* Skip some consistency checking. Good for benchmarking */#define SPEEDY/* Read return zeros. Undefine for benchmarking */#define CLEAR/* Number of real scsi disks that will be detected ahead of time */static int NR_REAL = -1;#define NR_BLK_DEV 12#ifndef MAJOR_NR#define MAJOR_NR 8#endif#define START_PARTITION 4/* Time to wait before completing a command */#define DISK_SPEED (HZ/10) /* 100ms */#define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)#define SIZE(TGT) (TGT == 2 ? 2248 : 512)static int starts[] ={N_SECTOR, N_HEAD * N_SECTOR, /* Single cylinder */ N_HEAD * N_SECTOR * 4, CAPACITY, 0};static int npart = 0;#include "scsi_debug.h"#ifdef DEBUG#define DEB(x) x#else#define DEB(x)#endif#ifdef SPEEDY#define VERIFY1_DEBUG(RW)#define VERIFY_DEBUG(RW)#else#define VERIFY1_DEBUG(RW) \ if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \ start = 0; \ if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \ if (bh){ \ if (bh->b_size != 1024) panic ("Wrong bh size"); \ if ((bh->b_blocknr << 1) + start != block) \ { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \ panic ("Wrong bh block#"); \ }; \ if (bh->b_dev != SCpnt->request.rq_dev) \ panic ("Bad bh target"); \ };#define VERIFY_DEBUG(RW) \ if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \ start = 0; \ if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition"); \ if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \ if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \ if (SCpnt->request.sector + start != block) panic("Wrong block."); \ if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \ if (SCpnt->request.bh){ \ if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \ if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \ { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \ panic ("Wrong bh block#"); \ }; \ if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \ panic ("Bad bh target");\ };#endiftypedef void (*done_fct_t) (Scsi_Cmnd *);static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] ={NULL,};struct Scsi_Host * SHpnt = NULL;static void scsi_debug_send_self_command(struct Scsi_Host * shpnt);static void scsi_debug_intr_handle(unsigned long);static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] ={NULL,};static char SCrst[SCSI_DEBUG_MAILBOXES] ={0,};/* * Semaphore used to simulate bus lockups. */static int scsi_debug_lockup = 0;static char sense_buffer[128] ={0,};static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){ int i;#if 0 unsigned char *pnt;#endif unsigned int *lpnt; struct scatterlist *sgpnt = NULL; printk("use_sg: %d", SCpnt->use_sg); if (SCpnt->use_sg) { sgpnt = (struct scatterlist *) SCpnt->buffer; for (i = 0; i < SCpnt->use_sg; i++) { lpnt = (int *) sgpnt[i].alt_address; printk(":%p %p %d\n", sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); if (lpnt) printk(" (Alt %x) ", lpnt[15]); }; } else { printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer, SCpnt->bufflen); lpnt = (int *) SCpnt->request.buffer; if (lpnt) printk(" (Alt %x) ", lpnt[15]); }; lpnt = (unsigned int *) SCpnt; for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { if ((i & 7) == 0) printk("\n"); printk("%x ", *lpnt++); }; printk("\n"); if (flag == 0) return; lpnt = (unsigned int *) sgpnt[0].alt_address; for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { if ((i & 7) == 0) printk("\n"); printk("%x ", *lpnt++); };#if 0 printk("\n"); lpnt = (unsigned int *) sgpnt[0].address; for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { if ((i & 7) == 0) printk("\n"); printk("%x ", *lpnt++); }; printk("\n");#endif printk("DMA free %d sectors.\n", scsi_dma_free_sectors);}int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)){ unchar *cmd = (unchar *) SCpnt->cmnd; struct partition *p; int block; struct buffer_head *bh = NULL; unsigned char *buff; int nbytes, sgcount; int scsi_debug_errsts; struct scatterlist *sgpnt; int target = SCpnt->target; int bufflen = SCpnt->request_bufflen; unsigned long flags; int i; sgcount = 0; sgpnt = NULL;#ifdef CONFIG_SMP /* * The io_request_lock *must* be held at this point. */ if( io_request_lock.lock == 0 ) { printk("Warning - io_request_lock is not held in queuecommand\n"); }#endif /* * If we are being notified of the mid-level reposessing a command due to timeout, * just return. */ if (done == NULL) { return 0; } DEB(if (target >= NR_FAKE_DISKS) { SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0; } ); buff = (unsigned char *) SCpnt->request_buffer; /* * If a command comes for the ID of the host itself, just print * a silly message and return. */ if( target == 7 ) { printk("How do you do!\n"); SCpnt->result = 0; done(SCpnt); return 0; } if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } if (SCrst[target] != 0 && !scsi_debug_lockup) { SCrst[target] = 0; memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); SCpnt->sense_buffer[0] = 0x70; SCpnt->sense_buffer[2] = UNIT_ATTENTION; SCpnt->result = (CHECK_CONDITION << 1); done(SCpnt); } switch (*cmd) { case REQUEST_SENSE: SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));#ifndef DEBUG { int i; printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen); for (i = 0; i < 12; i++) printk("%d ", sense_buffer[i]); printk("\n"); };#endif memset(buff, 0, bufflen); memcpy(buff, sense_buffer, bufflen); memset(sense_buffer, 0, sizeof(sense_buffer)); SCpnt->result = 0; done(SCpnt); return 0; case START_STOP: SCSI_LOG_LLQUEUE(3, printk("START_STOP\n")); scsi_debug_errsts = 0; break; case ALLOW_MEDIUM_REMOVAL: if (cmd[4]) { SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited...")); } else { SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled...")); } scsi_debug_errsts = 0; break; case INQUIRY: SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen)); memset(buff, 0, bufflen); buff[0] = DEVICE_TYPE(target); buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ buff[2] = 1; buff[4] = 33 - 5; memcpy(&buff[8], "Foo Inc", 7); memcpy(&buff[16], "XYZZY", 5); memcpy(&buff[32], "1", 1); scsi_debug_errsts = 0; break; case TEST_UNIT_READY: SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen)); if (buff) memset(buff, 0, bufflen); scsi_debug_errsts = 0; break; case READ_CAPACITY: SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n")); SHpnt = SCpnt->host; if (NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f; memset(buff, 0, bufflen); buff[0] = (CAPACITY >> 24); buff[1] = (CAPACITY >> 16) & 0xff; buff[2] = (CAPACITY >> 8) & 0xff; buff[3] = CAPACITY & 0xff; buff[4] = 0; buff[5] = 0; buff[6] = (SIZE(target) >> 8) & 0xff; /* 512 byte sectors */ buff[7] = SIZE(target) & 0xff; scsi_debug_errsts = 0; break; case READ_10: case READ_6:#ifdef DEBUG printk("Read...");#endif if ((*cmd) == READ_10) block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); else block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); VERIFY_DEBUG(READ);#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE) { int delay = SCSI_SETUP_LATENCY; delay += SCpnt->request.nr_sectors * SCSI_DATARATE; if (delay) usleep(delay); };#endif#ifdef DEBUG printk("(r%d)", SCpnt->request.nr_sectors);#endif nbytes = bufflen; if (SCpnt->use_sg) { sgcount = 0; sgpnt = (struct scatterlist *) buff; buff = sgpnt[sgcount].address; bufflen = sgpnt[sgcount].length; bh = SCpnt->request.bh; }; scsi_debug_errsts = 0; do { VERIFY1_DEBUG(READ); /* For the speedy test, we do not even want to fill the buffer with anything */#ifdef CLEAR memset(buff, 0, bufflen);#endif /* If this is block 0, then we want to read the partition table for this * device. Let's make one up */ if (block == 0) { int i; memset(buff, 0, bufflen); *((unsigned short *) (buff + 510)) = 0xAA55; p = (struct partition *) (buff + 0x1be); i = 0; while (starts[i + 1]) { int start_cyl, end_cyl; start_cyl = starts[i] / N_HEAD / N_SECTOR; end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR; p->boot_ind = 0; p->head = (i == 0 ? 1 : 0); p->sector = 1 | ((start_cyl >> 8) << 6); p->cyl = (start_cyl & 0xff); p->end_head = N_HEAD - 1; p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6); p->end_cyl = (end_cyl & 0xff); p->start_sect = starts[i]; p->nr_sects = starts[i + 1] - starts[i]; p->sys_ind = 0x81; /* Linux partition */ p++; i++; }; if (!npart) npart = i; scsi_debug_errsts = 0; break; };#ifdef DEBUG if (SCpnt->use_sg) printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors, SCpnt->request.current_nr_sectors);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -