From: Ben Gras Date: Thu, 4 Aug 2005 08:08:58 +0000 (+0000) Subject: Do test transaction before letting open device succeed; if probe fails, X-Git-Tag: v3.1.0~459 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/man.dnssec-dsfromkey.html?a=commitdiff_plain;h=93460d0ad07787e3fd461bc002926fc43adebc71;p=minix.git Do test transaction before letting open device succeed; if probe fails, remember drive isn't there and don't try it again --- diff --git a/drivers/at_wini/at_wini.c b/drivers/at_wini/at_wini.c index d0a664697..572cab717 100644 --- a/drivers/at_wini/at_wini.c +++ b/drivers/at_wini/at_wini.c @@ -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);