?? scsi.c
字號:
so we can use it */
if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
(memcmp("Floptical F*8I", &scsi_result[16], 16) == 0
|| memcmp("I325VM", &scsi_result[16], 6) == 0)) {
printk("Unlocked floptical drive.\n");
scsi_devices[NR_SCSI_DEVICES].lockable = 0;
scsi_cmd[0] = MODE_SENSE;
scsi_cmd[1] = (lun << 5) & 0xe0;
scsi_cmd[2] = 0x2e;
scsi_cmd[3] = 0;
scsi_cmd[4] = 0x2a;
scsi_cmd[5] = 0;
SCmd.request.dev = 0xffff; /* Mark not busy */
scsi_do_cmd (&SCmd,
(void *) scsi_cmd, (void *)
scsi_result, 0x2a, scan_scsis_done,
SCSI_TIMEOUT, 3);
while (SCmd.request.dev != 0xfffe);
};
++NR_SCSI_DEVICES;
/* Some scsi devices cannot be polled for lun != 0
due to firmware bugs */
if(blacklisted(scsi_result)) break;
/* Old drives like the MAXTOR XT-3280 say vers=0 */
if ((scsi_result[2] & 0x07) == 0)
break;
/* Some scsi-1 peripherals do not handle lun != 0.
I am assuming that scsi-2 peripherals do better */
if((scsi_result[2] & 0x07) == 1 &&
(scsi_result[3] & 0x0f) == 0) break;
}
} /* if result == DID_OK ends */
} /* for lun ends */
shpnt->host_queue = NULL; /* No longer needed here */
} /* if present */
printk("scsi : detected ");
if(NR_SD != -1)
printk("%d SCSI disk%s ", MAX_SD, (MAX_SD != 1) ? "s" : "");
if(NR_ST != -1)
printk("%d tape%s ", MAX_ST, (MAX_ST != 1) ? "s" : "");
if(NR_SR != -1)
printk("%d CD-ROM drive%s ", MAX_SR, (MAX_SR != 1) ? "s" : "");
printk("total.\n");
in_scan = 0;
} /* scan_scsis ends */
/*
* Flag bits for the internal_timeout array
*/
#define NORMAL_TIMEOUT 0
#define IN_ABORT 1
#define IN_RESET 2
/*
This is our time out function, called when the timer expires for a
given host adapter. It will attempt to abort the currently executing
command, that failing perform a kernel panic.
*/
static void scsi_times_out (Scsi_Cmnd * SCpnt)
{
switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
{
case NORMAL_TIMEOUT:
if (!in_scan)
printk("SCSI host %d timed out - aborting command\n",
SCpnt->host->host_no);
if (!scsi_abort (SCpnt, DID_TIME_OUT))
return;
case IN_ABORT:
printk("SCSI host %d abort() timed out - reseting\n",
SCpnt->host->host_no);
if (!scsi_reset (SCpnt))
return;
case IN_RESET:
case (IN_ABORT | IN_RESET):
panic("Unable to reset scsi host %d\n",SCpnt->host->host_no);
default:
INTERNAL_ERROR;
}
}
/* 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, int index)
{
Scsi_Cmnd * SCpnt = NULL;
int tablesize;
struct buffer_head * bh;
if ((index < 0) || (index > NR_SCSI_DEVICES))
panic ("Index number in allocate_device() is out of range.\n");
if (req && req->dev <= 0)
panic("Invalid device in allocate_device");
SCpnt = scsi_devices[index].host->host_queue;
while(SCpnt){
if(SCpnt->target == scsi_devices[index].id &&
SCpnt->lun == scsi_devices[index].lun)
if(SCpnt->request.dev < 0) break;
SCpnt = SCpnt->next;
};
if (!SCpnt) return NULL;
if (scsi_devices[index].host->hostt->can_queue
&& scsi_devices[index].host->host_busy >= scsi_devices[index].host->hostt->can_queue) return NULL;
if (req) {
memcpy(&SCpnt->request, req, sizeof(struct request));
tablesize = scsi_devices[index].host->sg_tablesize;
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){
tablesize--;
req->nr_sectors -= bh->b_size >> 9;
req->sector += bh->b_size >> 9;
if(!tablesize) break;
bh = bh->b_reqnext;
};
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.waiting = NULL; /* Wait until whole thing done */
} else
req->dev = -1;
} else {
SCpnt->request.dev = 0xffff; /* Busy, but no request */
SCpnt->request.waiting = 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;
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, int index, int wait)
{
int dev = -1;
struct request * req = NULL;
int tablesize;
struct buffer_head * bh;
struct Scsi_Host * host;
Scsi_Cmnd * SCpnt = NULL;
Scsi_Cmnd * SCwait = NULL;
if ((index < 0) || (index > NR_SCSI_DEVICES))
panic ("Index number in allocate_device() is out of range.\n");
if (reqp) req = *reqp;
/* See if this request has already been queued by an interrupt routine */
if (req && (dev = req->dev) <= 0) return NULL;
host = scsi_devices[index].host;
while (1==1){
SCpnt = host->host_queue;
while(SCpnt){
if(SCpnt->target == scsi_devices[index].id &&
SCpnt->lun == scsi_devices[index].lun) {
SCwait = SCpnt;
if(SCpnt->request.dev < 0) break;
};
SCpnt = SCpnt->next;
};
cli();
/* See if this request has already been queued by an interrupt routine */
if (req && ((req->dev < 0) || (req->dev != dev))) {
sti();
return NULL;
};
if (!SCpnt || SCpnt->request.dev >= 0) /* Might have changed */
{
sti();
if(!wait) return NULL;
if (!SCwait) {
printk("Attempt to allocate device index %d, target %d, lun %d\n",
index, scsi_devices[index].id ,scsi_devices[index].lun);
panic("No device found in allocate_device\n");
};
SCSI_SLEEP(&scsi_devices[SCwait->index].device_wait,
(SCwait->request.dev > 0));
} else {
if (req) {
memcpy(&SCpnt->request, req, sizeof(struct request));
tablesize = scsi_devices[index].host->sg_tablesize;
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){
tablesize--;
req->nr_sectors -= bh->b_size >> 9;
req->sector += bh->b_size >> 9;
if(!tablesize) break;
bh = bh->b_reqnext;
};
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.waiting = NULL; /* Wait until whole thing done */
}
else
{
req->dev = -1;
*reqp = req->next;
};
} else {
SCpnt->request.dev = 0xffff; /* Busy */
SCpnt->request.waiting = NULL; /* And no one is waiting for this to complete */
};
sti();
break;
};
};
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
SCpnt->old_use_sg = 0;
SCpnt->transfersize = 0; /* No default transfer size */
SCpnt->underflow = 0; /* Do not flag underflow conditions */
return SCpnt;
}
/*
This is inline because we have stack problemes if we recurse to deeply.
*/
inline void internal_cmnd (Scsi_Cmnd * SCpnt)
{
int temp;
struct Scsi_Host * host;
#ifdef DEBUG_DELAY
int clock;
#endif
if ((unsigned long) &SCpnt < current->kernel_stack_page)
panic("Kernel stack overflow.");
host = SCpnt->host;
/*
We will wait MIN_RESET_DELAY clock ticks after the last reset so
we can avoid the drive not being ready.
*/
temp = host->last_reset;
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->host_no, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
#endif
if (host->hostt->can_queue)
{
#ifdef DEBUG
printk("queuecommand : routine at %08x\n",
host->hostt->queuecommand);
#endif
host->hostt->queuecommand (SCpnt, scsi_done);
}
else
{
#ifdef DEBUG
printk("command() : routine at %08x\n", host->hostt->command);
#endif
temp=host->hostt->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->host_no, 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 | ASKED_FOR_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);
SCpnt->use_sg = 0;
internal_cmnd (SCpnt);
SCpnt->use_sg = SCpnt->old_use_sg;
}
/*
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
)
{
struct Scsi_Host * 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->host_no, target, buffer, bufflen, done, timeout, retries);
for (i = 0; i < 10; ++i)
printk ("%02x ", ((unsigned char *) cmnd)[i]);
printk("\n");
};
#endif
if (!host)
{
panic ("Invalid or not present host. %d\n", host->host_no);
}
/*
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 (host->hostt->can_queue
&& host->host_busy >= host->hostt->can_queue)
{
sti();
SCSI_SLEEP(&host->host_wait,
(host->host_busy >= host->hostt->can_queue));
} else {
host->host_busy++;
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, 12);
#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;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -