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
					
				| @ -141,8 +141,6 @@ struct command { | |||||||
| /* Some controllers don't interrupt, the clock will wake us up. */ | /* Some controllers don't interrupt, the clock will wake us up. */ | ||||||
| #define WAKEUP		(32*HZ)	/* drive may be out for 31 seconds max */ | #define WAKEUP		(32*HZ)	/* drive may be out for 31 seconds max */ | ||||||
| 
 | 
 | ||||||
| int wakeup_ticks = WAKEUP; |  | ||||||
| 
 |  | ||||||
| /* Miscellaneous. */ | /* Miscellaneous. */ | ||||||
| #define MAX_DRIVES         4	/* this driver supports 4 drives (d0 - d3) */ | #define MAX_DRIVES         4	/* this driver supports 4 drives (d0 - d3) */ | ||||||
| #if _WORD_SIZE > 2 | #if _WORD_SIZE > 2 | ||||||
| @ -168,8 +166,13 @@ int wakeup_ticks = WAKEUP; | |||||||
| #define ATAPI		   0	/* don't bother with ATAPI; optimise out */ | #define ATAPI		   0	/* don't bother with ATAPI; optimise out */ | ||||||
| #endif | #endif | ||||||
| #define IDENTIFIED	0x10	/* w_identify done successfully */ | #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 timeout_ticks = DEF_TIMEOUT_TICKS, max_errors = MAX_ERRORS; | ||||||
|  | int wakeup_ticks = WAKEUP; | ||||||
|  | 
 | ||||||
|  | int w_testing = 0; | ||||||
| 
 | 
 | ||||||
| /* Variables. */ | /* Variables. */ | ||||||
| PRIVATE struct wini {		/* main drive struct, one entry per drive */ | 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 */ |   struct device subpart[SUB_PER_DRIVE];	/* subpartitions */ | ||||||
| } wini[MAX_DRIVES], *w_wn; | } 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 win_tasknr;			/* my task number */ | ||||||
| PRIVATE int w_command;			/* current command in execution */ | PRIVATE int w_command;			/* current command in execution */ | ||||||
| PRIVATE u8_t w_byteval;			/* used for SYS_IRQCTL */ | 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( int w_identify, (void) ); | ||||||
| FORWARD _PROTOTYPE( char *w_name, (void) ); | FORWARD _PROTOTYPE( char *w_name, (void) ); | ||||||
| FORWARD _PROTOTYPE( int w_specify, (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, | FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, off_t position, | ||||||
| 					iovec_t *iov, unsigned nr_req) ); | 					iovec_t *iov, unsigned nr_req) ); | ||||||
| FORWARD _PROTOTYPE( int com_out, (struct command *cmd) ); | FORWARD _PROTOTYPE( int com_out, (struct command *cmd) ); | ||||||
| @ -321,16 +328,41 @@ message *m_ptr; | |||||||
| 
 | 
 | ||||||
|   wn = w_wn; |   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. */ | 	/* Try to identify the device. */ | ||||||
| 	if (w_identify() != OK) { | 	if (w_identify() != OK) { | ||||||
|   		printf("%s: probe failed\n", w_name()); |   		printf("%s: probe failed\n", w_name()); | ||||||
| 		if (wn->state & DEAF) w_reset(); | 		if (wn->state & DEAF) w_reset(); | ||||||
| 		wn->state = 0; | 		wn->state = IGNORING; | ||||||
| 		return(ENXIO); | 		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 (wn->open_ct == 0) { | ||||||
| #if ENABLE_ATAPI | #if ENABLE_ATAPI | ||||||
| 	if (wn->state & ATAPI) { | 	if (wn->state & ATAPI) { | ||||||
| @ -340,6 +372,9 @@ message *m_ptr; | |||||||
| 		if ((r = atapi_open()) != OK) return(r); | 		if ((r = atapi_open()) != OK) return(r); | ||||||
| 	} | 	} | ||||||
| #endif | #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 the disk. */ | ||||||
| 	partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY); | 	partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY); | ||||||
| 	wn->open_ct++; | 	wn->open_ct++; | ||||||
| @ -356,6 +391,7 @@ int device; | |||||||
| { | { | ||||||
| /* Prepare for I/O on a device. */ | /* Prepare for I/O on a device. */ | ||||||
| 
 | 
 | ||||||
|  |   w_device = device; | ||||||
|   if (device < NR_DEVICES) {			/* d0, d0p[0-3], d1, ... */ |   if (device < NR_DEVICES) {			/* d0, d0p[0-3], d1, ... */ | ||||||
| 	w_drive = device / DEV_PER_DRIVE;	/* save drive number */ | 	w_drive = device / DEV_PER_DRIVE;	/* save drive number */ | ||||||
| 	w_wn = &wini[w_drive]; | 	w_wn = &wini[w_drive]; | ||||||
| @ -366,6 +402,7 @@ int device; | |||||||
| 	w_wn = &wini[w_drive]; | 	w_wn = &wini[w_drive]; | ||||||
| 	w_dv = &w_wn->subpart[device % SUB_PER_DRIVE]; | 	w_dv = &w_wn->subpart[device % SUB_PER_DRIVE]; | ||||||
|   } else { |   } else { | ||||||
|  |   	w_device = -1; | ||||||
| 	return(NIL_DEV); | 	return(NIL_DEV); | ||||||
|   } |   } | ||||||
|   return(w_dv); |   return(w_dv); | ||||||
| @ -383,7 +420,6 @@ PRIVATE int w_identify() | |||||||
| 
 | 
 | ||||||
|   struct wini *wn = w_wn; |   struct wini *wn = w_wn; | ||||||
|   struct command cmd; |   struct command cmd; | ||||||
|   char id_string[40]; |  | ||||||
|   int i, r, s; |   int i, r, s; | ||||||
|   unsigned long size; |   unsigned long size; | ||||||
| #define id_byte(n)	(&tmp_buf[2 * (n)]) | #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); | 		panic(w_name(),"Call to sys_insw() failed", s); | ||||||
| 
 | 
 | ||||||
| 	/* Why are the strings byte swapped??? */ | 	/* 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. */ | 	/* Preferred CHS translation mode. */ | ||||||
| 	wn->pcylinders = id_word(1); | 	wn->pcylinders = id_word(1); | ||||||
| @ -443,7 +479,7 @@ PRIVATE int w_identify() | |||||||
| 		panic(w_name(),"Call to sys_insw() failed", s); | 		panic(w_name(),"Call to sys_insw() failed", s); | ||||||
| 
 | 
 | ||||||
| 	/* Why are the strings byte swapped??? */ | 	/* 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. */ | 	size = 0;	/* Size set later. */ | ||||||
| #endif | #endif | ||||||
| @ -461,6 +497,7 @@ PRIVATE int w_identify() | |||||||
|   /* Size of the whole drive */ |   /* Size of the whole drive */ | ||||||
|   wn->part[0].dv_size = mul64u(size, SECTOR_SIZE); |   wn->part[0].dv_size = mul64u(size, SECTOR_SIZE); | ||||||
| 
 | 
 | ||||||
|  |   /* Reset/calibrate (where necessary) */ | ||||||
|   if (w_specify() != OK && w_specify() != OK) { |   if (w_specify() != OK && w_specify() != OK) { | ||||||
|   	return(ERR); |   	return(ERR); | ||||||
|   } |   } | ||||||
| @ -498,6 +535,59 @@ PRIVATE char *w_name() | |||||||
|   return 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				     * |  *				w_specify				     * | ||||||
| @ -564,6 +654,8 @@ unsigned nr_req;		/* length of request vector */ | |||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |    | ||||||
|  | 
 | ||||||
|   /* Check disk address. */ |   /* Check disk address. */ | ||||||
|   if ((position & SECTOR_MASK) != 0) return(EINVAL); |   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() */ |   pvb_pair_t outbyte[7];		/* vector for sys_voutb() */ | ||||||
|   int s;				/* status for sys_(v)outb() */ |   int s;				/* status for sys_(v)outb() */ | ||||||
| 
 | 
 | ||||||
|  |   if(w_wn->state & IGNORING) return ERR; | ||||||
|  | 
 | ||||||
|   if (!w_waitfor(STATUS_BSY, 0)) { |   if (!w_waitfor(STATUS_BSY, 0)) { | ||||||
| 	printf("%s: controller not ready\n", w_name()); | 	printf("%s: controller not ready\n", w_name()); | ||||||
| 	return(ERR); | 	return(ERR); | ||||||
| @ -756,6 +850,8 @@ struct command *cmd;		/* Command block */ | |||||||
| /* A simple controller command, only one interrupt and no data-out phase. */ | /* A simple controller command, only one interrupt and no data-out phase. */ | ||||||
|   int r; |   int r; | ||||||
| 
 | 
 | ||||||
|  |   if(w_wn->state & IGNORING) return ERR; | ||||||
|  | 
 | ||||||
|   if ((r = com_out(cmd)) == OK) r = at_intr_wait(); |   if ((r = com_out(cmd)) == OK) r = at_intr_wait(); | ||||||
|   w_command = CMD_IDLE; |   w_command = CMD_IDLE; | ||||||
|   return(r); |   return(r); | ||||||
| @ -785,7 +881,8 @@ PRIVATE void w_timeout(void) | |||||||
| 	/*FALL THROUGH*/ | 	/*FALL THROUGH*/ | ||||||
|   default: |   default: | ||||||
| 	/* Some other command. */ | 	/* 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_need_reset(); | ||||||
| 	w_status = 0; | 	w_status = 0; | ||||||
|   } |   } | ||||||
| @ -801,7 +898,10 @@ PRIVATE int w_reset() | |||||||
|  * like the controller refusing to respond. |  * like the controller refusing to respond. | ||||||
|  */ |  */ | ||||||
|   int s; |   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. */ |   /* Wait for any internal drive recovery. */ | ||||||
|   tickdelay(RECOVERY_TICKS); |   tickdelay(RECOVERY_TICKS); | ||||||
| @ -1100,6 +1200,8 @@ unsigned cnt; | |||||||
|   pvb_pair_t outbyte[6];		/* vector for sys_voutb() */ |   pvb_pair_t outbyte[6];		/* vector for sys_voutb() */ | ||||||
|   int s; |   int s; | ||||||
| 
 | 
 | ||||||
|  |   if(wn->state & IGNORING) return ERR; | ||||||
|  | 
 | ||||||
|   /* Select Master/Slave drive */ |   /* Select Master/Slave drive */ | ||||||
|   if ((s=sys_outb(wn->base + REG_DRIVE, wn->ldhpref)) != OK) |   if ((s=sys_outb(wn->base + REG_DRIVE, wn->ldhpref)) != OK) | ||||||
|   	panic(w_name(),"Couldn't select master/ slave drive",s); |   	panic(w_name(),"Couldn't select master/ slave drive",s); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Ben Gras
						Ben Gras