?? scsi.c
字號:
break; } } else { status = FINISHED; break; } /* fall through to REDO */ case REDO: if (SCpnt->flags & WAS_SENSE) scsi_request_sense(SCpnt); else { memcpy ((void *) SCpnt->cmnd, (void*) SCpnt->data_cmnd, sizeof(SCpnt->data_cmnd)); SCpnt->request_buffer = SCpnt->buffer; SCpnt->request_bufflen = SCpnt->bufflen; internal_cmnd (SCpnt); }; break; default: INTERNAL_ERROR; } if (status == FINISHED) { #ifdef DEBUG printk("Calling done function - at address %08x\n", SCpnt->done); #endif host_busy[host]--; /* Indicate that we are free */ wake_up(&host_wait[host]); SCpnt->result = result | ((exit & 0xff) << 24); SCpnt->done (SCpnt); }#undef FINISHED#undef REDO#undef MAYREDO#undef PENDING }/* The scsi_abort function interfaces with the abort() function of the host we are aborting, and causes the current command to not complete. The caller should deal with any error messages or status returned on the next call. This will not be called rentrantly for a given host.*/ /* 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; int 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_busy[host] || !scsi_hosts[host].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; int host = SCpnt->host; #ifdef DEBUG printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",host);#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_busy[host]) { sti(); SCpnt1 = host_queue[host]; 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 = scsi_hosts[host].reset(); } else { host_busy[host]++; sti(); temp = scsi_hosts[host].reset(); last_reset[host] = jiffies; host_busy[host]--; } 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, 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 = 0; host < max_scsi_hosts; host++) { SCpnt = host_queue[host]; 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(); }/* These are used to keep track of things. */static int time_start, time_elapsed;/* 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, host; unsigned int oldto; 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 = 0; host < max_scsi_hosts; host++) { SCpnt = host_queue[host]; 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;char *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(char *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; int host; Scsi_Cmnd * SCpnt;#ifdef FOO_ON_YOU return;#endif timer_table[SCSI_TIMER].fn = scsi_main_timeout; timer_table[SCSI_TIMER].expires = 0; scsi_init(); /* initialize all hosts */ for (i = 0; i < max_scsi_hosts; ++i) last_reset[i] = 0; 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); 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; }; if(scsi_devices[i].type != -1){ for(j=0;j<scsi_hosts[scsi_devices[i].host_no].cmd_per_lun;j++){ SCpnt->host = scsi_devices[i].host_no; 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; host = scsi_devices[i].host_no; if(host_queue[host]) host_queue[host]->prev = SCpnt; SCpnt->next = host_queue[host]; SCpnt->prev = NULL; host_queue[host] = 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) { int host; host = scsi_devices[i].host_no; if(scsi_devices[i].type != TYPE_TAPE) dma_sectors += ((scsi_hosts[host].sg_tablesize * sizeof(struct scatterlist) + 511) >> 9) * scsi_hosts[host].cmd_per_lun; if(scsi_hosts[host].unchecked_isa_dma && memory_end > ISA_DMA_THRESHOLD && scsi_devices[i].type != TYPE_TAPE) { dma_sectors += 32 * scsi_hosts[host].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 = (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); return memory_start; }static void print_inquiry(unsigned char *data){ int i; printk(" Vendor: "); for (i = 8; i < 16; i++) { if (data[i] >= 20 && i < data[4] + 5) printk("%c", data[i]); else printk(" "); } printk(" Model: "); for (i = 16; i < 32; i++) { if (data[i] >= 20 && i < data[4] + 5) printk("%c", data[i]); else printk(" "); } printk(" Rev: "); for (i = 32; i < 36; i++) { if (data[i] >= 20 && i < data[4] + 5) printk("%c", data[i]); else printk(" "); } printk("\n"); i = data[0] & 0x1f; printk(" Type: %s ", i == 0x00 ? "Direct-Access " : i == 0x01 ? "Sequential-Access" : i == 0x02 ? "Printer " : i == 0x03 ? "Processor " : i == 0x04 ? "WORM " : i == 0x05 ? "CD-ROM " : i == 0x06 ? "Scanner " : i == 0x07 ? "Optical Device " : i == 0x08 ? "Medium Changer " : i == 0x09 ? "Communications " : "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 + -