Do test transaction before letting open device succeed; if probe fails,
remember drive isn't there and don't try it again
This commit is contained in:
parent
2be2bce18c
commit
93460d0ad0
1 changed files with 111 additions and 9 deletions
|
@ -141,8 +141,6 @@ struct command {
|
|||
/* Some controllers don't interrupt, the clock will wake us up. */
|
||||
#define WAKEUP (32*HZ) /* drive may be out for 31 seconds max */
|
||||
|
||||
int wakeup_ticks = WAKEUP;
|
||||
|
||||
/* Miscellaneous. */
|
||||
#define MAX_DRIVES 4 /* this driver supports 4 drives (d0 - d3) */
|
||||
#if _WORD_SIZE > 2
|
||||
|
@ -168,8 +166,13 @@ int wakeup_ticks = WAKEUP;
|
|||
#define ATAPI 0 /* don't bother with ATAPI; optimise out */
|
||||
#endif
|
||||
#define IDENTIFIED 0x10 /* w_identify done successfully */
|
||||
#define IGNORING 0x20 /* w_identify failed once */
|
||||
|
||||
/* Timeouts and max retries. */
|
||||
int timeout_ticks = DEF_TIMEOUT_TICKS, max_errors = MAX_ERRORS;
|
||||
int wakeup_ticks = WAKEUP;
|
||||
|
||||
int w_testing = 0;
|
||||
|
||||
/* Variables. */
|
||||
PRIVATE struct wini { /* main drive struct, one entry per drive */
|
||||
|
@ -191,6 +194,9 @@ PRIVATE struct wini { /* main drive struct, one entry per drive */
|
|||
struct device subpart[SUB_PER_DRIVE]; /* subpartitions */
|
||||
} wini[MAX_DRIVES], *w_wn;
|
||||
|
||||
PRIVATE int w_device = -1;
|
||||
PRIVATE char w_id_string[40];
|
||||
|
||||
PRIVATE int win_tasknr; /* my task number */
|
||||
PRIVATE int w_command; /* current command in execution */
|
||||
PRIVATE u8_t w_byteval; /* used for SYS_IRQCTL */
|
||||
|
@ -204,6 +210,7 @@ FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
|
|||
FORWARD _PROTOTYPE( int w_identify, (void) );
|
||||
FORWARD _PROTOTYPE( char *w_name, (void) );
|
||||
FORWARD _PROTOTYPE( int w_specify, (void) );
|
||||
FORWARD _PROTOTYPE( int w_io_test, (void) );
|
||||
FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, off_t position,
|
||||
iovec_t *iov, unsigned nr_req) );
|
||||
FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
|
||||
|
@ -321,16 +328,41 @@ message *m_ptr;
|
|||
|
||||
wn = w_wn;
|
||||
|
||||
if (!(wn->state & (IDENTIFIED)) || (wn->state & DEAF)) {
|
||||
/* If we've probed it before and it failed, don't probe it again. */
|
||||
if (wn->state & IGNORING) return ENXIO;
|
||||
|
||||
/* If we haven't identified it yet, or it's gone deaf,
|
||||
* (re-)identify it.
|
||||
*/
|
||||
if (!(wn->state & IDENTIFIED) || (wn->state & DEAF)) {
|
||||
/* Try to identify the device. */
|
||||
if (w_identify() != OK) {
|
||||
printf("%s: probe failed\n", w_name());
|
||||
if (wn->state & DEAF) w_reset();
|
||||
wn->state = 0;
|
||||
wn->state = IGNORING;
|
||||
return(ENXIO);
|
||||
}
|
||||
/* Do a test transaction unless it's a CD drive (then
|
||||
* we can believe the controller, and a test may fail
|
||||
* due to no CD being in the drive). If it fails, ignore
|
||||
* the device forever.
|
||||
*/
|
||||
if(!(wn->state & ATAPI) && w_io_test() != OK) {
|
||||
wn->state |= IGNORING;
|
||||
return(ENXIO);
|
||||
}
|
||||
|
||||
printf("%s: AT driver detected ", w_name());
|
||||
if (wn->state & (SMART|ATAPI)) {
|
||||
printf("%.40s\n", w_id_string);
|
||||
} else {
|
||||
printf("%ux%ux%u\n", wn->pcylinders, wn->pheads, wn->psectors);
|
||||
}
|
||||
}
|
||||
|
||||
/* Partition the drive if it's being opened for the first time,
|
||||
* or being opened after being closed.
|
||||
*/
|
||||
if (wn->open_ct == 0) {
|
||||
#if ENABLE_ATAPI
|
||||
if (wn->state & ATAPI) {
|
||||
|
@ -340,6 +372,9 @@ message *m_ptr;
|
|||
if ((r = atapi_open()) != OK) return(r);
|
||||
}
|
||||
#endif
|
||||
/* If it's not an ATAPI device, then don't open read-only. */
|
||||
if (!(wn->state & ATAPI) && (m_ptr->COUNT & RO_BIT)) return EACCES;
|
||||
|
||||
/* Partition the disk. */
|
||||
partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
|
||||
wn->open_ct++;
|
||||
|
@ -356,6 +391,7 @@ int device;
|
|||
{
|
||||
/* Prepare for I/O on a device. */
|
||||
|
||||
w_device = device;
|
||||
if (device < NR_DEVICES) { /* d0, d0p[0-3], d1, ... */
|
||||
w_drive = device / DEV_PER_DRIVE; /* save drive number */
|
||||
w_wn = &wini[w_drive];
|
||||
|
@ -366,6 +402,7 @@ int device;
|
|||
w_wn = &wini[w_drive];
|
||||
w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
|
||||
} else {
|
||||
w_device = -1;
|
||||
return(NIL_DEV);
|
||||
}
|
||||
return(w_dv);
|
||||
|
@ -383,7 +420,6 @@ PRIVATE int w_identify()
|
|||
|
||||
struct wini *wn = w_wn;
|
||||
struct command cmd;
|
||||
char id_string[40];
|
||||
int i, r, s;
|
||||
unsigned long size;
|
||||
#define id_byte(n) (&tmp_buf[2 * (n)])
|
||||
|
@ -406,7 +442,7 @@ PRIVATE int w_identify()
|
|||
panic(w_name(),"Call to sys_insw() failed", s);
|
||||
|
||||
/* Why are the strings byte swapped??? */
|
||||
for (i = 0; i < 40; i++) id_string[i] = id_byte(27)[i^1];
|
||||
for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1];
|
||||
|
||||
/* Preferred CHS translation mode. */
|
||||
wn->pcylinders = id_word(1);
|
||||
|
@ -443,7 +479,7 @@ PRIVATE int w_identify()
|
|||
panic(w_name(),"Call to sys_insw() failed", s);
|
||||
|
||||
/* Why are the strings byte swapped??? */
|
||||
for (i = 0; i < 40; i++) id_string[i] = id_byte(27)[i^1];
|
||||
for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1];
|
||||
|
||||
size = 0; /* Size set later. */
|
||||
#endif
|
||||
|
@ -461,6 +497,7 @@ PRIVATE int w_identify()
|
|||
/* Size of the whole drive */
|
||||
wn->part[0].dv_size = mul64u(size, SECTOR_SIZE);
|
||||
|
||||
/* Reset/calibrate (where necessary) */
|
||||
if (w_specify() != OK && w_specify() != OK) {
|
||||
return(ERR);
|
||||
}
|
||||
|
@ -498,6 +535,59 @@ PRIVATE char *w_name()
|
|||
return name;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* w_io_test *
|
||||
*===========================================================================*/
|
||||
PRIVATE int w_io_test(void)
|
||||
{
|
||||
int r, save_dev;
|
||||
int save_timeout, save_errors, save_wakeup;
|
||||
iovec_t iov;
|
||||
#ifdef CD_SECTOR_SIZE
|
||||
static char buf[CD_SECTOR_SIZE];
|
||||
#else
|
||||
static char buf[SECTOR_SIZE];
|
||||
#endif
|
||||
|
||||
iov.iov_addr = (vir_bytes) buf;
|
||||
iov.iov_size = sizeof(buf);
|
||||
save_dev = w_device;
|
||||
|
||||
/* Reduce timeout values for this test transaction. */
|
||||
save_timeout = timeout_ticks;
|
||||
save_errors = max_errors;
|
||||
save_wakeup = wakeup_ticks;
|
||||
|
||||
timeout_ticks = HZ * 2;
|
||||
wakeup_ticks = HZ * 5;
|
||||
max_errors = 2;
|
||||
w_testing = 1;
|
||||
|
||||
/* Try I/O on the actual drive (not any (sub)partition). */
|
||||
if(w_prepare(w_drive * DEV_PER_DRIVE) == NIL_DEV)
|
||||
panic(w_name(), "Couldn't switch devices", NO_NUM);
|
||||
|
||||
r = w_transfer(SELF, DEV_GATHER, 0, &iov, 1);
|
||||
|
||||
/* Switch back. */
|
||||
if(w_prepare(save_dev) == NIL_DEV)
|
||||
panic(w_name(), "Couldn't switch back devices", NO_NUM);
|
||||
|
||||
/* Restore parameters. */
|
||||
timeout_ticks = save_timeout;
|
||||
max_errors = save_errors;
|
||||
wakeup_ticks = save_wakeup;
|
||||
w_testing = 0;
|
||||
|
||||
/* Test if everything worked. */
|
||||
if(r != OK || iov.iov_size != 0) {
|
||||
return ERR;
|
||||
}
|
||||
|
||||
/* Everything worked. */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* w_specify *
|
||||
|
@ -564,6 +654,8 @@ unsigned nr_req; /* length of request vector */
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Check disk address. */
|
||||
if ((position & SECTOR_MASK) != 0) return(EINVAL);
|
||||
|
||||
|
@ -677,6 +769,8 @@ struct command *cmd; /* Command block */
|
|||
pvb_pair_t outbyte[7]; /* vector for sys_voutb() */
|
||||
int s; /* status for sys_(v)outb() */
|
||||
|
||||
if(w_wn->state & IGNORING) return ERR;
|
||||
|
||||
if (!w_waitfor(STATUS_BSY, 0)) {
|
||||
printf("%s: controller not ready\n", w_name());
|
||||
return(ERR);
|
||||
|
@ -756,6 +850,8 @@ struct command *cmd; /* Command block */
|
|||
/* A simple controller command, only one interrupt and no data-out phase. */
|
||||
int r;
|
||||
|
||||
if(w_wn->state & IGNORING) return ERR;
|
||||
|
||||
if ((r = com_out(cmd)) == OK) r = at_intr_wait();
|
||||
w_command = CMD_IDLE;
|
||||
return(r);
|
||||
|
@ -785,7 +881,8 @@ PRIVATE void w_timeout(void)
|
|||
/*FALL THROUGH*/
|
||||
default:
|
||||
/* Some other command. */
|
||||
printf("%s: timeout on command %02x\n", w_name(), w_command);
|
||||
if(w_testing) wn->state |= IGNORING; /* Kick out this drive. */
|
||||
else printf("%s: timeout on command %02x\n", w_name(), w_command);
|
||||
w_need_reset();
|
||||
w_status = 0;
|
||||
}
|
||||
|
@ -801,7 +898,10 @@ PRIVATE int w_reset()
|
|||
* like the controller refusing to respond.
|
||||
*/
|
||||
int s;
|
||||
struct wini *wn;
|
||||
struct wini *wn = w_wn;
|
||||
|
||||
/* Don't bother if this drive is forgotten. */
|
||||
if(w_wn->state & IGNORING) return ERR;
|
||||
|
||||
/* Wait for any internal drive recovery. */
|
||||
tickdelay(RECOVERY_TICKS);
|
||||
|
@ -1100,6 +1200,8 @@ unsigned cnt;
|
|||
pvb_pair_t outbyte[6]; /* vector for sys_voutb() */
|
||||
int s;
|
||||
|
||||
if(wn->state & IGNORING) return ERR;
|
||||
|
||||
/* Select Master/Slave drive */
|
||||
if ((s=sys_outb(wn->base + REG_DRIVE, wn->ldhpref)) != OK)
|
||||
panic(w_name(),"Couldn't select master/ slave drive",s);
|
||||
|
|
Loading…
Reference in a new issue