📄 scsi.c
字号:
/* Obviously the bus reset didn't work. * Let's try even harder and call for an HBA reset. * Maybe the HBA itself crashed and this will shake it loose. */ printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n", SCpnt->host->host_no, SCpnt->pid); SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2); SCpnt->internal_timeout |= IN_RESET3; scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET); return; default: printk("SCSI host %d reset (pid %ld) timed out again -\n", SCpnt->host->host_no, SCpnt->pid); printk("probably an unrecoverable SCSI bus or device hang.\n"); return; } }/* This function takes a quick look at a request, and decides if it * can be queued now, or if there would be a stall while waiting for * something else to finish. This routine assumes that interrupts are * turned off when entering the routine. It is the responsibility * of the calling code to ensure that this is the case. */Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device){ Scsi_Cmnd * SCpnt = NULL; int tablesize; Scsi_Cmnd * found = NULL; struct buffer_head * bh, *bhp; if (!device) panic ("No device passed to request_queueable().\n"); if (req && req->rq_status == RQ_INACTIVE) panic("Inactive in request_queueable"); /* * Look for a free command block. If we have been instructed not to queue * multiple commands to multi-lun devices, then check to see what else is * going for this device first. */ if (!device->single_lun) { SCpnt = device->device_queue; while(SCpnt){ if(SCpnt->request.rq_status == RQ_INACTIVE) break; SCpnt = SCpnt->device_next; } } else { SCpnt = device->host->host_queue; while(SCpnt){ if(SCpnt->channel == device->channel && SCpnt->target == device->id) { if (SCpnt->lun == device->lun) { if(found == NULL && SCpnt->request.rq_status == RQ_INACTIVE) { found=SCpnt; } } if(SCpnt->request.rq_status != RQ_INACTIVE) { /* * I think that we should really limit things to one * outstanding command per device - this is what tends * to trip up buggy firmware. */ return NULL; } } SCpnt = SCpnt->next; } SCpnt = found; } if (!SCpnt) return NULL; if (SCSI_BLOCK(device->host)) return NULL; if (req) { memcpy(&SCpnt->request, req, sizeof(struct request)); tablesize = device->host->sg_tablesize; bhp = bh = req->bh; if(!tablesize) bh = NULL; /* Take a quick look through the table to see how big it is. * We already have our copy of req, so we can mess with that * if we want to. */ while(req->nr_sectors && bh){ bhp = bhp->b_reqnext; if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--; req->nr_sectors -= bh->b_size >> 9; req->sector += bh->b_size >> 9; if(!tablesize) break; bh = bhp; } if(req->nr_sectors && bh && bh->b_reqnext){ /* Any leftovers? */ SCpnt->request.bhtail = bh; req->bh = bh->b_reqnext; /* Divide request */ bh->b_reqnext = NULL; bh = req->bh; /* Now reset things so that req looks OK */ SCpnt->request.nr_sectors -= req->nr_sectors; req->current_nr_sectors = bh->b_size >> 9; req->buffer = bh->b_data; SCpnt->request.sem = NULL; /* Wait until whole thing done */ } else { req->rq_status = RQ_INACTIVE; wake_up(&wait_for_request); } } else { SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Busy, but no request */ SCpnt->request.sem = NULL; /* And no one is waiting for the device * either */ } SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; SCpnt->underflow = 0; SCpnt->cmd_len = 0;/* Since not everyone seems to set the device info correctly * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. */ SCpnt->channel = device->channel; SCpnt->lun = device->lun; SCpnt->target = device->id; return SCpnt;}/* This function returns a structure pointer that will be valid for * the device. The wait parameter tells us whether we should wait for * the unit to become free or not. We are also able to tell this routine * not to return a descriptor if the host is unable to accept any more * commands for the time being. We need to keep in mind that there is no * guarantee that the host remain not busy. Keep in mind the * request_queueable function also knows the internal allocation scheme * of the packets for each device */Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device, int wait){ kdev_t dev; struct request * req = NULL; int tablesize; unsigned long flags; struct buffer_head * bh, *bhp; struct Scsi_Host * host; Scsi_Cmnd * SCpnt = NULL; Scsi_Cmnd * SCwait = NULL; Scsi_Cmnd * found = NULL; if (!device) panic ("No device passed to allocate_device().\n"); if (reqp) req = *reqp; /* See if this request has already been queued by an interrupt routine */ if (req) { if(req->rq_status == RQ_INACTIVE) return NULL; dev = req->rq_dev; } else dev = 0; /* unused */ host = device->host; if (intr_count && SCSI_BLOCK(host)) return NULL; while (1==1){ if (!device->single_lun) { SCpnt = device->device_queue; while(SCpnt){ SCwait = SCpnt; if(SCpnt->request.rq_status == RQ_INACTIVE) break; SCpnt = SCpnt->device_next; } } else { SCpnt = device->host->host_queue; while(SCpnt){ if(SCpnt->channel == device->channel && SCpnt->target == device->id) { if (SCpnt->lun == device->lun) { SCwait = SCpnt; if(found == NULL && SCpnt->request.rq_status == RQ_INACTIVE) { found=SCpnt; } } if(SCpnt->request.rq_status != RQ_INACTIVE) { /* * I think that we should really limit things to one * outstanding command per device - this is what tends * to trip up buggy firmware. */ found = NULL; break; } } SCpnt = SCpnt->next; } SCpnt = found; } save_flags(flags); cli(); /* See if this request has already been queued by an interrupt routine */ if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) { restore_flags(flags); return NULL; } if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) /* Might have changed */ {#if 1 /* NEW CODE */ if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){ sleep_on(&device->device_wait); restore_flags(flags); } else { restore_flags(flags); if (!wait) return NULL; if (!SCwait) { printk("Attempt to allocate device channel %d," " target %d, lun %d\n", device->channel, device->id, device->lun); panic("No device found in allocate_device\n"); } }#else /* ORIGINAL CODE */ restore_flags(flags); if(!wait) return NULL; if (!SCwait) { printk("Attempt to allocate device channel %d, target" " %d, lun %d\n", device->channel, device->id, device->lun); panic("No device found in allocate_device\n"); } SCSI_SLEEP(&device->device_wait, (SCwait->request.rq_status != RQ_INACTIVE));#endif } else { if (req) { memcpy(&SCpnt->request, req, sizeof(struct request)); tablesize = device->host->sg_tablesize; bhp = bh = req->bh; if(!tablesize) bh = NULL; /* Take a quick look through the table to see how big it is. * We already have our copy of req, so we can mess with that * if we want to. */ while(req->nr_sectors && bh){ bhp = bhp->b_reqnext; if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--; req->nr_sectors -= bh->b_size >> 9; req->sector += bh->b_size >> 9; if(!tablesize) break; bh = bhp; } if(req->nr_sectors && bh && bh->b_reqnext){/* Any leftovers? */ SCpnt->request.bhtail = bh; req->bh = bh->b_reqnext; /* Divide request */ bh->b_reqnext = NULL; bh = req->bh; /* Now reset things so that req looks OK */ SCpnt->request.nr_sectors -= req->nr_sectors; req->current_nr_sectors = bh->b_size >> 9; req->buffer = bh->b_data; SCpnt->request.sem = NULL; /* Wait until whole thing done*/ } else { req->rq_status = RQ_INACTIVE; *reqp = req->next; wake_up(&wait_for_request); } } else { SCpnt->request.rq_status = RQ_SCSI_BUSY; SCpnt->request.sem = NULL; /* And no one is waiting for this * to complete */ } restore_flags(flags); break; } } SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; /* No default transfer size */ SCpnt->cmd_len = 0; SCpnt->underflow = 0; /* Do not flag underflow conditions */ /* Since not everyone seems to set the device info correctly * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. */ SCpnt->channel = device->channel; SCpnt->lun = device->lun; SCpnt->target = device->id; return SCpnt;}/* * This is inline because we have stack problemes if we recurse to deeply. */inline void internal_cmnd (Scsi_Cmnd * SCpnt){ unsigned long flags, timeout; struct Scsi_Host * host;#ifdef DEBUG_DELAY unsigned long clock;#endif#if DEBUG unsigned long *ret = 0;#ifdef __mips__ __asm__ __volatile__ ("move\t%0,$31":"=r"(ret));#else ret = __builtin_return_address(0);#endif#endif host = SCpnt->host; save_flags(flags); cli(); /* Assign a unique nonzero serial_number. */ if (++serial_number == 0) serial_number = 1; SCpnt->serial_number = serial_number; /* * We will wait MIN_RESET_DELAY clock ticks after the last reset so * we can avoid the drive not being ready. */ timeout = host->last_reset + MIN_RESET_DELAY; if (jiffies < timeout) { int ticks_remaining = timeout - jiffies; /* * NOTE: This may be executed from within an interrupt * handler! This is bad, but for now, it'll do. The irq * level of the interrupt handler has been masked out by the * platform dependent interrupt handling code already, so the * sti() here will not cause another call to the SCSI host's * interrupt handler (assuming there is one irq-level per * host). */ sti(); while (--ticks_remaining >= 0) udelay(1000000/HZ); host->last_reset = jiffies - MIN_RESET_DELAY; } restore_flags(flags); update_timeout(SCpnt, SCpnt->timeout_per_command); /* * We will use a queued command if possible, otherwise we will emulate the * queuing and calling of completion function ourselves. */#ifdef DEBUG printk("internal_cmnd (host = %d, channel = %d, target = %d, " "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done);#endif if (host->can_queue) {#ifdef DEBUG printk("queuecommand : routine at %p\n", host->hostt->queuecommand);#endif /* This locking tries to prevent all sorts of races between * queuecommand and the interrupt code. In effect, * we are only allowed to be in queuecommand once at * any given time, and we can only be in the interrupt * handler and the queuecommand function at the same time * when queuecommand is called while servicing the * interrupt. */ if(!intr_count && SCpnt->host->irq) disable_irq(SCpnt->host->irq); host->hostt->queuecommand (SCpnt, scsi_done); if(!intr_count && SCpnt->host->irq) enable_irq(SCpnt->host->irq); } else { int temp;#ifdef DEBUG printk("command() : routine at %p\n", host->hostt->command);#endif temp = host->hostt->command (SCpnt); SCpnt->result = temp;#ifdef DEBUG_DELAY clock = jiffies + 4 * HZ; while (jiffies < clock) barrier(); printk("done(host = %d, result = %04x) : routine at %p\n", host->host_no, temp, host->hostt->command);#endif scsi_done(SCpnt); }#ifdef DEBUG printk("leaving internal_cmnd()\n");#endif}static void scsi_request_sense (Scsi_Cmnd * SCpnt){ unsigned long flags; save_flags(flags); cli(); SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE; update_timeout(SCpnt, SENSE_TIMEOUT); restore_flags(flags); 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); SCpnt->use_sg = 0; SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); internal_cmnd (SCpnt);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -