?? scsi.c
字號:
} else { if (req) { memcpy(&SCpnt->request, req, sizeof(struct request)); req->dev = -1; *reqp = req->next; } else { SCpnt->request.dev = 0xffff; /* Busy */ }; sti(); break; }; }; SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ return SCpnt;}/* This is inline because we have stack problemes if we recurse to deeply.*/ inline void internal_cmnd (Scsi_Cmnd * SCpnt) { int temp, host;#ifdef DEBUG_DELAY int clock;#endif host = SCpnt->host; if ((host < 0) || (host > max_scsi_hosts)) panic ("Host number in internal_cmnd() is out of range.\n");/* We will wait MIN_RESET_DELAY clock ticks after the last reset so we can avoid the drive not being ready.*/ temp = last_reset[host];while (jiffies < temp);update_timeout(SCpnt, SCpnt->timeout_per_command);/* We will use a queued command if possible, otherwise we will emulate the queing and calling of completion function ourselves. */#ifdef DEBUG printk("internal_cmnd (host = %d, target = %d, command = %08x, buffer = %08x, \n" "bufflen = %d, done = %08x)\n", SCpnt->host, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done);#endif if (scsi_hosts[host].can_queue) {#ifdef DEBUG printk("queuecommand : routine at %08x\n", scsi_hosts[host].queuecommand);#endif scsi_hosts[host].queuecommand (SCpnt, scsi_done); } else {#ifdef DEBUG printk("command() : routine at %08x\n", scsi_hosts[host].command);#endif temp=scsi_hosts[host].command (SCpnt); SCpnt->result = temp;#ifdef DEBUG_DELAY clock = jiffies + 400; while (jiffies < clock); printk("done(host = %d, result = %04x) : routine at %08x\n", host, temp, done);#endif scsi_done(SCpnt); } #ifdef DEBUG printk("leaving internal_cmnd()\n");#endif } static void scsi_request_sense (Scsi_Cmnd * SCpnt) { cli(); SCpnt->flags |= WAS_SENSE; update_timeout(SCpnt, SENSE_TIMEOUT); sti(); memcpy ((void *) SCpnt->cmnd , (void *) generic_sense, sizeof(generic_sense)); SCpnt->cmnd[1] = SCpnt->lun << 5; SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); SCpnt->request_buffer = &SCpnt->sense_buffer; SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); internal_cmnd (SCpnt); }/* scsi_do_cmd sends all the commands out to the low-level driver. It handles the specifics required for each low level driver - ie queued or non queud. It also prevents conflicts when different high level drivers go for the same host at the same time.*/void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *), int timeout, int retries ) { int host = SCpnt->host;#ifdef DEBUG { int i; int target = SCpnt->target; printk ("scsi_do_cmd (host = %d, target = %d, buffer =%08x, " "bufflen = %d, done = %08x, timeout = %d, retries = %d)\n" "command : " , host, target, buffer, bufflen, done, timeout, retries); for (i = 0; i < 10; ++i) printk ("%02x ", ((unsigned char *) cmnd)[i]); printk("\n"); };#endif if ((host < 0) || (host >= max_scsi_hosts) || !scsi_hosts[host].present) { printk ("Invalid or not present host number. %d\n", host); panic(""); } /* We must prevent reentrancy to the lowlevel host driver. This prevents it - we enter a loop until the host we want to talk to is not busy. Race conditions are prevented, as interrupts are disabled inbetween the time we check for the host being not busy, and the time we mark it busy ourselves.*/ while (1==1){ cli(); if (scsi_hosts[host].can_queue && host_busy[host] >= scsi_hosts[host].can_queue) { sti(); SCSI_SLEEP(&host_wait[host], (host_busy[host] >= scsi_hosts[host].can_queue)); } else { host_busy[host]++; sti(); break; }; };/* Our own function scsi_done (which marks the host as not busy, disables the timeout counter, etc) will be called by us or by the scsi_hosts[host].queuecommand() function needs to also call the completion function for the high level driver.*/ memcpy ((void *) SCpnt->data_cmnd , (void *) cmnd, 10);#if 0 SCpnt->host = host; SCpnt->target = target; SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);#endif SCpnt->bufflen = bufflen; SCpnt->buffer = buffer; SCpnt->flags=0; SCpnt->retries=0; SCpnt->allowed=retries; SCpnt->done = done; SCpnt->timeout_per_command = timeout; memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 10); SCpnt->request_buffer = buffer; SCpnt->request_bufflen = bufflen; /* Start the timer ticking. */ SCpnt->internal_timeout = 0; internal_cmnd (SCpnt);#ifdef DEBUG printk ("Leaving scsi_do_cmd()\n");#endif }/* The scsi_done() function disables the timeout timer for the scsi host, marks the host as not busy, and calls the user specified completion function for that host's current command.*/static void reset (Scsi_Cmnd * SCpnt) { #ifdef DEBUG printk("reset(%d)\n", SCpnt->host); #endif SCpnt->flags |= (WAS_RESET | IS_RESETTING); scsi_reset(SCpnt); #ifdef DEBUG printk("performing request sense\n"); #endif scsi_request_sense (SCpnt); } static int check_sense (Scsi_Cmnd * SCpnt) { if (((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { if (SCpnt->sense_buffer[2] &0xe0) return SUGGEST_ABORT; switch (SCpnt->sense_buffer[2] & 0xf) { case NO_SENSE: case RECOVERED_ERROR: return 0; case ABORTED_COMMAND: case NOT_READY: return SUGGEST_RETRY; case UNIT_ATTENTION: return SUGGEST_ABORT; /* these three are not supported */ case COPY_ABORTED: case VOLUME_OVERFLOW: case MISCOMPARE: case MEDIUM_ERROR: return SUGGEST_REMAP; case BLANK_CHECK: case DATA_PROTECT: case HARDWARE_ERROR: case ILLEGAL_REQUEST: default: return SUGGEST_ABORT; } } else return SUGGEST_RETRY; } /* This function is the mid-level interrupt routine, which decides how * to handle error conditions. Each invocation of this function must * do one and *only* one of the following: * * (1) Call last_cmnd[host].done. This is done for fatal errors and * normal completion, and indicates that the handling for this * request is complete. * (2) Call internal_cmnd to requeue the command. This will result in * scsi_done being called again when the retry is complete. * (3) Call scsi_request_sense. This asks the host adapter/drive for * more information about the error condition. When the information * is available, scsi_done will be called again. * (4) Call reset(). This is sort of a last resort, and the idea is that * this may kick things loose and get the drive working again. reset() * automatically calls scsi_request_sense, and thus scsi_done will be * called again once the reset is complete. * * If none of the above actions are taken, the drive in question * will hang. If more than one of the above actions are taken by * scsi_done, then unpredictable behavior will result. */static void scsi_done (Scsi_Cmnd * SCpnt) { int status=0; int exit=0; int checked; int oldto; int host = SCpnt->host; int result = SCpnt->result; oldto = update_timeout(SCpnt, 0);#define FINISHED 0#define MAYREDO 1#define REDO 3#define PENDING 4#ifdef DEBUG printk("In scsi_done(host = %d, result = %06x)\n", host, result);#endif if (host > max_scsi_hosts || host < 0) { update_timeout(SCpnt, 0); panic("scsi_done() called with invalid host number.\n"); } switch (host_byte(result)) { case DID_OK: if (SCpnt->flags & IS_RESETTING) { SCpnt->flags &= ~IS_RESETTING; status = REDO; break; } if (status_byte(result) && (SCpnt->flags & WAS_SENSE)) /* Failed to obtain sense information */ { SCpnt->flags &= ~WAS_SENSE; SCpnt->internal_timeout &= ~SENSE_TIMEOUT; if (!(SCpnt->flags & WAS_RESET)) { reset(SCpnt); return; } else { exit = (DRIVER_HARD | SUGGEST_ABORT); status = FINISHED; } } else switch(msg_byte(result)) { case COMMAND_COMPLETE: switch (status_byte(result)) { case GOOD: if (SCpnt->flags & WAS_SENSE) {#ifdef DEBUG printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");#endif SCpnt->flags &= ~WAS_SENSE; SCpnt->internal_timeout &= ~SENSE_TIMEOUT; switch (checked = check_sense(SCpnt)) { case 0: #ifdef DEBUG printk("NO SENSE. status = REDO\n");#endif update_timeout(SCpnt, oldto); status = REDO; break; case SUGGEST_REMAP: case SUGGEST_RETRY: #ifdef DEBUG printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");#endif status = MAYREDO; exit = DRIVER_SENSE | SUGGEST_RETRY; break; case SUGGEST_ABORT:#ifdef DEBUG printk("SENSE SUGGEST ABORT - status = FINISHED");#endif status = FINISHED; exit = DRIVER_SENSE | SUGGEST_ABORT; break; default: printk ("Internal error %s %s \n", __FILE__, __LINE__); } } else {#ifdef DEBUG printk("COMMAND COMPLETE message returned, status = FINISHED. \n");#endif exit = DRIVER_OK; status = FINISHED; } break; case CHECK_CONDITION:#ifdef DEBUG printk("CHECK CONDITION message returned, performing request sense.\n");#endif scsi_request_sense (SCpnt); status = PENDING; break; case CONDITION_GOOD: case INTERMEDIATE_GOOD: case INTERMEDIATE_C_GOOD:#ifdef DEBUG printk("CONDITION GOOD, INTERMEDIATE GOOD, or INTERMEDIATE CONDITION GOOD recieved and ignored. \n");#endif break; case BUSY:#ifdef DEBUG printk("BUSY message returned, performing REDO");#endif update_timeout(SCpnt, oldto); status = REDO; break; case RESERVATION_CONFLICT: reset(SCpnt); return;#if 0 exit = DRIVER_SOFT | SUGGEST_ABORT; status = MAYREDO; break;#endif default: printk ("Internal error %s %s \n" "status byte = %d \n", __FILE__, __LINE__, status_byte(result)); } break; default: panic ("unsupported message byte recieved."); } break; case DID_TIME_OUT: #ifdef DEBUG printk("Host returned DID_TIME_OUT - ");#endif if (SCpnt->flags & WAS_TIMEDOUT) {#ifdef DEBUG printk("Aborting\n");#endif exit = (DRIVER_TIMEOUT | SUGGEST_ABORT); } else {#ifdef DEBUG printk ("Retrying.\n");#endif SCpnt->flags |= WAS_TIMEDOUT; status = REDO; } break; case DID_BUS_BUSY: case DID_PARITY: status = REDO; break; case DID_NO_CONNECT:#ifdef DEBUG printk("Couldn't connect.\n");#endif exit = (DRIVER_HARD | SUGGEST_ABORT); break; case DID_ERROR: status = MAYREDO; exit = (DRIVER_HARD | SUGGEST_ABORT); break; case DID_BAD_TARGET: case DID_ABORT: exit = (DRIVER_INVALID | SUGGEST_ABORT); break; default : exit = (DRIVER_ERROR | SUGGEST_DIE); } switch (status) { case FINISHED: case PENDING: break; case MAYREDO:#ifdef DEBUG printk("In MAYREDO, allowing %d retries, have %d\n\r", SCpnt->allowed, SCpnt->retries);#endif if ((++SCpnt->retries) < SCpnt->allowed) { if ((SCpnt->retries >= (SCpnt->allowed >> 1)) && !(SCpnt->flags & WAS_RESET)) { reset(SCpnt);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -