?? scsi.c
字號:
*/
/*
Since we're nice guys and specified that abort() and reset()
can be non-reentrant. The internal_timeout flags are used for
this.
*/
int scsi_abort (Scsi_Cmnd * SCpnt, int why)
{
int temp, oldto;
struct Scsi_Host * host = SCpnt->host;
while(1)
{
cli();
if (SCpnt->internal_timeout & IN_ABORT)
{
sti();
while (SCpnt->internal_timeout & IN_ABORT);
}
else
{
SCpnt->internal_timeout |= IN_ABORT;
oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
sti();
if (!host->host_busy || !host->hostt->abort(SCpnt, why))
temp = 0;
else
temp = 1;
cli();
SCpnt->internal_timeout &= ~IN_ABORT;
update_timeout(SCpnt, oldto);
sti();
return temp;
}
}
}
int scsi_reset (Scsi_Cmnd * SCpnt)
{
int temp, oldto;
Scsi_Cmnd * SCpnt1;
struct Scsi_Host * host = SCpnt->host;
#ifdef DEBUG
printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",host->host_no);
#endif
while (1) {
cli();
if (SCpnt->internal_timeout & IN_RESET)
{
sti();
while (SCpnt->internal_timeout & IN_RESET);
}
else
{
SCpnt->internal_timeout |= IN_RESET;
oldto = update_timeout(SCpnt, RESET_TIMEOUT);
if (host->host_busy)
{
sti();
SCpnt1 = host->host_queue;
while(SCpnt1) {
if ((SCpnt1->request.dev > 0) &&
!(SCpnt1->flags & IS_RESETTING) &&
!(SCpnt1->internal_timeout & IN_ABORT))
scsi_abort(SCpnt1, DID_RESET);
SCpnt1 = SCpnt1->next;
};
temp = host->hostt->reset(SCpnt);
}
else
{
host->host_busy++;
sti();
temp = host->hostt->reset(SCpnt);
host->last_reset = jiffies;
host->host_busy--;
}
cli();
SCpnt->internal_timeout &= ~IN_RESET;
update_timeout(SCpnt, oldto);
sti();
return temp;
}
}
}
static void scsi_main_timeout(void)
{
/*
We must not enter update_timeout with a timeout condition still pending.
*/
int timed_out;
struct Scsi_Host * host;
Scsi_Cmnd * SCpnt = NULL;
do {
cli();
/*
Find all timers such that they have 0 or negative (shouldn't happen)
time remaining on them.
*/
timed_out = 0;
for(host = scsi_hostlist; host; host = host->next) {
SCpnt = host->host_queue;
while (SCpnt){
if (SCpnt->timeout > 0 && SCpnt->timeout <= time_elapsed)
{
sti();
SCpnt->timeout = 0;
scsi_times_out(SCpnt);
++timed_out;
cli();
}
SCpnt = SCpnt->next;
};
};
update_timeout(NULL, 0);
} while (timed_out);
sti();
}
/*
The strategy is to cause the timer code to call scsi_times_out()
when the soonest timeout is pending.
The arguments are used when we are queueing a new command, because
we do not want to subtract the time used from this time, but when we
set the timer, we want to take this value into account.
*/
static int update_timeout(Scsi_Cmnd * SCset, int timeout)
{
unsigned int least, used;
unsigned int oldto;
struct Scsi_Host * host;
Scsi_Cmnd * SCpnt = NULL;
cli();
/*
Figure out how much time has passed since the last time the timeouts
were updated
*/
used = (time_start) ? (jiffies - time_start) : 0;
/*
Find out what is due to timeout soonest, and adjust all timeouts for
the amount of time that has passed since the last time we called
update_timeout.
*/
oldto = 0;
if(SCset){
oldto = SCset->timeout - used;
SCset->timeout = timeout + used;
};
least = 0xffffffff;
for(host = scsi_hostlist; host; host = host->next) {
SCpnt = host->host_queue;
while (SCpnt){
if (SCpnt->timeout > 0 && (SCpnt->timeout -= used) < least)
least = SCpnt->timeout;
SCpnt = SCpnt->next;
};
};
/*
If something is due to timeout again, then we will set the next timeout
interrupt to occur. Otherwise, timeouts are disabled.
*/
if (least != 0xffffffff)
{
time_start = jiffies;
timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
timer_active |= 1 << SCSI_TIMER;
}
else
{
timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
timer_active &= ~(1 << SCSI_TIMER);
}
sti();
return oldto;
}
static unsigned short * dma_malloc_freelist = NULL;
static unsigned int dma_sectors = 0;
unsigned int dma_free_sectors = 0;
unsigned int need_isa_buffer = 0;
static unsigned char * dma_malloc_buffer = NULL;
void *scsi_malloc(unsigned int len)
{
unsigned int nbits, mask;
int i, j;
if((len & 0x1ff) || len > 4096)
panic("Inappropriate buffer size requested");
cli();
nbits = len >> 9;
mask = (1 << nbits) - 1;
for(i=0;i < (dma_sectors >> 4); i++)
for(j=0; j<17-nbits; j++){
if ((dma_malloc_freelist[i] & (mask << j)) == 0){
dma_malloc_freelist[i] |= (mask << j);
sti();
dma_free_sectors -= nbits;
#ifdef DEBUG
printk("SMalloc: %d %x ",len, dma_malloc_buffer + (i << 13) + (j << 9));
#endif
return (void *) ((unsigned long) dma_malloc_buffer + (i << 13) + (j << 9));
};
};
sti();
return NULL; /* Nope. No more */
}
int scsi_free(void *obj, unsigned int len)
{
int offset;
int page, sector, nbits, mask;
#ifdef DEBUG
printk("Sfree %x %d\n",obj, len);
#endif
offset = ((int) obj) - ((int) dma_malloc_buffer);
if (offset < 0) panic("Bad offset");
page = offset >> 13;
sector = offset >> 9;
if(sector >= dma_sectors) panic ("Bad page");
sector = (offset >> 9) & 15;
nbits = len >> 9;
mask = (1 << nbits) - 1;
if ((mask << sector) > 0xffff) panic ("Bad memory alignment");
cli();
if(dma_malloc_freelist[page] & (mask << sector) != (mask<<sector))
panic("Trying to free unused memory");
dma_free_sectors += nbits;
dma_malloc_freelist[page] &= ~(mask << sector);
sti();
return 0;
}
/*
scsi_dev_init() is our initialization routine, which inturn calls host
initialization, bus scanning, and sd/st initialization routines. It
should be called from main().
*/
unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end)
{
int i;
struct Scsi_Host * host;
Scsi_Cmnd * SCpnt;
#ifdef FOO_ON_YOU
return;
#endif
timer_table[SCSI_TIMER].fn = scsi_main_timeout;
timer_table[SCSI_TIMER].expires = 0;
/* initialize all hosts */
memory_start = scsi_init(memory_start, memory_end);
scsi_devices = (Scsi_Device *) memory_start;
scan_scsis(); /* scan for scsi devices */
memory_start += NR_SCSI_DEVICES * sizeof(Scsi_Device);
memory_start = sd_init1(memory_start, memory_end);
memory_start = st_init1(memory_start, memory_end);
memory_start = sr_init1(memory_start, memory_end);
memory_start = sg_init1(memory_start, memory_end);
last_cmnd = (Scsi_Cmnd *) memory_start;
SCpnt = last_cmnd;
for (i=0; i< NR_SCSI_DEVICES; i++) {
int j;
switch (scsi_devices[i].type)
{
case TYPE_TAPE :
st_attach(&scsi_devices[i]);
break;
case TYPE_ROM:
sr_attach(&scsi_devices[i]);
break;
case TYPE_DISK:
case TYPE_MOD:
sd_attach(&scsi_devices[i]);
default:
break;
};
sg_attach(&scsi_devices[i]);
if(scsi_devices[i].type != -1){
for(j=0;j<scsi_devices[i].host->hostt->cmd_per_lun;j++){
SCpnt->host = scsi_devices[i].host;
SCpnt->target = scsi_devices[i].id;
SCpnt->lun = scsi_devices[i].lun;
SCpnt->index = i;
SCpnt->request.dev = -1; /* Mark not busy */
SCpnt->use_sg = 0;
SCpnt->old_use_sg = 0;
SCpnt->underflow = 0;
SCpnt->transfersize = 0;
SCpnt->host_scribble = NULL;
host = scsi_devices[i].host;
if(host->host_queue)
host->host_queue->prev = SCpnt;
SCpnt->next = host->host_queue;
SCpnt->prev = NULL;
host->host_queue = SCpnt;
SCpnt++;
};
};
};
memory_start = (int) SCpnt;
if (NR_SD > 0 || NR_SR > 0 || NR_ST > 0)
dma_sectors = 16; /* Base value we use */
for (i = 0; i < NR_SCSI_DEVICES; ++i) {
struct Scsi_Host * host;
host = scsi_devices[i].host;
if(scsi_devices[i].type != TYPE_TAPE)
dma_sectors += ((host->sg_tablesize *
sizeof(struct scatterlist) + 511) >> 9) *
host->hostt->cmd_per_lun;
if(host->unchecked_isa_dma &&
memory_end > ISA_DMA_THRESHOLD &&
scsi_devices[i].type != TYPE_TAPE) {
dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
host->hostt->cmd_per_lun;
need_isa_buffer++;
};
};
dma_sectors = (dma_sectors + 15) & 0xfff0;
dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */
memory_start = (memory_start + 3) & 0xfffffffc;
dma_malloc_freelist = (unsigned short *) memory_start;
memory_start += dma_sectors >> 3;
memset(dma_malloc_freelist, 0, dma_sectors >> 3);
if(memory_start & 1) memory_start++; /* Some host adapters require
buffers to be word aligned */
dma_malloc_buffer = (unsigned char *) memory_start;
memory_start += dma_sectors << 9;
memory_start = sd_init(memory_start, memory_end); /* init scsi disks */
memory_start = st_init(memory_start, memory_end); /* init scsi tapes */
memory_start = sr_init(memory_start, memory_end); /* init scsi CDROMs */
memory_start = sg_init(memory_start, memory_end); /* init scsi generic */
return memory_start;
}
static void print_inquiry(unsigned char *data)
{
int i;
printk(" Vendor: ");
for (i = 8; i < 16; i++)
{
if (data[i] >= 0x20 && i < data[4] + 5)
printk("%c", data[i]);
else
printk(" ");
}
printk(" Model: ");
for (i = 16; i < 32; i++)
{
if (data[i] >= 0x20 && i < data[4] + 5)
printk("%c", data[i]);
else
printk(" ");
}
printk(" Rev: ");
for (i = 32; i < 36; i++)
{
if (data[i] >= 0x20 && i < data[4] + 5)
printk("%c", data[i]);
else
printk(" ");
}
printk("\n");
i = data[0] & 0x1f;
printk(" Type: %s ",
i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown " );
printk(" ANSI SCSI revision: %02x", data[2] & 0x07);
if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
printk(" CCS\n");
else
printk("\n");
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -