⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at_wini.c

📁 minix3的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
 *===========================================================================*/PRIVATE int w_transfer(proc_nr, opcode, position, iov, nr_req)int proc_nr;			/* process doing the request */int opcode;			/* DEV_GATHER or DEV_SCATTER */off_t position;			/* offset on device to read or write */iovec_t *iov;			/* pointer to read or write request vector */unsigned nr_req;		/* length of request vector */{  struct wini *wn = w_wn;  iovec_t *iop, *iov_end = iov + nr_req;  int r, s, errors;  unsigned long block;  unsigned long dv_size = cv64ul(w_dv->dv_size);  unsigned cylinder, head, sector, nbytes;#if ENABLE_ATAPI  if (w_wn->state & ATAPI) {	return atapi_transfer(proc_nr, opcode, position, iov, nr_req);  }#endif    /* Check disk address. */  if ((position & SECTOR_MASK) != 0) return(EINVAL);  errors = 0;  while (nr_req > 0) {	/* How many bytes to transfer? */	nbytes = 0;	for (iop = iov; iop < iov_end; iop++) nbytes += iop->iov_size;	if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);	/* Which block on disk and how close to EOF? */	if (position >= dv_size) return(OK);		/* At EOF */	if (position + nbytes > dv_size) nbytes = dv_size - position;	block = div64u(add64ul(w_dv->dv_base, position), SECTOR_SIZE);	if (nbytes >= wn->max_count) {		/* The drive can't do more then max_count at once. */		nbytes = wn->max_count;	}	/* First check to see if a reinitialization is needed. */	if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);	/* Tell the controller to transfer nbytes bytes. */	r = do_transfer(wn, wn->precomp, ((nbytes >> SECTOR_SHIFT) & BYTE),		block, opcode);	while (r == OK && nbytes > 0) {		/* For each sector, wait for an interrupt and fetch the data		 * (read), or supply data to the controller and wait for an		 * interrupt (write).		 */		if (opcode == DEV_GATHER) {			/* First an interrupt, then data. */			if ((r = at_intr_wait()) != OK) {				/* An error, send data to the bit bucket. */				if (w_wn->w_status & STATUS_DRQ) {	if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK)		panic(w_name(),"Call to sys_insw() failed", s);				}				break;			}		}		/* Wait for data transfer requested. */		if (!w_waitfor(STATUS_DRQ, STATUS_DRQ)) { r = ERR; break; }		/* Copy bytes to or from the device's buffer. */		if (opcode == DEV_GATHER) {	if ((s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK)		panic(w_name(),"Call to sys_insw() failed", s);		} else {	if ((s=sys_outsw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK)		panic(w_name(),"Call to sys_insw() failed", s);			/* Data sent, wait for an interrupt. */			if ((r = at_intr_wait()) != OK) break;		}		/* Book the bytes successfully transferred. */		nbytes -= SECTOR_SIZE;		position += SECTOR_SIZE;		iov->iov_addr += SECTOR_SIZE;		if ((iov->iov_size -= SECTOR_SIZE) == 0) { iov++; nr_req--; }	}	/* Any errors? */	if (r != OK) {		/* Don't retry if sector marked bad or too many errors. */		if (r == ERR_BAD_SECTOR || ++errors == max_errors) {			w_command = CMD_IDLE;			return(EIO);		}	}  }  w_command = CMD_IDLE;  return(OK);}/*===========================================================================* *				com_out					     * *===========================================================================*/PRIVATE int com_out(cmd)struct command *cmd;		/* Command block */{/* Output the command block to the winchester controller and return status */  struct wini *wn = w_wn;  unsigned base_cmd = wn->base_cmd;  unsigned base_ctl = wn->base_ctl;  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);  }  /* Select drive. */  if ((s=sys_outb(base_cmd + REG_LDH, cmd->ldh)) != OK)  	panic(w_name(),"Couldn't write register to select drive",s);  if (!w_waitfor(STATUS_BSY, 0)) {	printf("%s: com_out: drive not ready\n", w_name());	return(ERR);  }  /* Schedule a wakeup call, some controllers are flaky. This is done with   * a synchronous alarm. If a timeout occurs a SYN_ALARM message is sent   * from HARDWARE, so that w_intr_wait() can call w_timeout() in case the   * controller was not able to execute the command. Leftover timeouts are   * simply ignored by the main loop.    */  sys_setalarm(wakeup_ticks, 0);  wn->w_status = STATUS_ADMBSY;  w_command = cmd->command;  pv_set(outbyte[0], base_ctl + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);  pv_set(outbyte[1], base_cmd + REG_PRECOMP, cmd->precomp);  pv_set(outbyte[2], base_cmd + REG_COUNT, cmd->count);  pv_set(outbyte[3], base_cmd + REG_SECTOR, cmd->sector);  pv_set(outbyte[4], base_cmd + REG_CYL_LO, cmd->cyl_lo);  pv_set(outbyte[5], base_cmd + REG_CYL_HI, cmd->cyl_hi);  pv_set(outbyte[6], base_cmd + REG_COMMAND, cmd->command);  if ((s=sys_voutb(outbyte,7)) != OK)  	panic(w_name(),"Couldn't write registers with sys_voutb()",s);  return(OK);}/*===========================================================================* *				w_need_reset				     * *===========================================================================*/PRIVATE void w_need_reset(){/* The controller needs to be reset. */  struct wini *wn;  int dr = 0;  for (wn = wini; wn < &wini[MAX_DRIVES]; wn++, dr++) {	if (wn->base_cmd == w_wn->base_cmd) {		wn->state |= DEAF;		wn->state &= ~INITIALIZED;	}  }}/*===========================================================================* *				w_do_close				     * *===========================================================================*/PRIVATE int w_do_close(dp, m_ptr)struct driver *dp;message *m_ptr;{/* Device close: Release a device. */  if (w_prepare(m_ptr->DEVICE) == NIL_DEV)  	return(ENXIO);  w_wn->open_ct--;#if ENABLE_ATAPI  if (w_wn->open_ct == 0 && (w_wn->state & ATAPI)) atapi_close();#endif  return(OK);}/*===========================================================================* *				com_simple				     * *===========================================================================*/PRIVATE int com_simple(cmd)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);}/*===========================================================================* *				w_timeout				     * *===========================================================================*/PRIVATE void w_timeout(void){  struct wini *wn = w_wn;  switch (w_command) {  case CMD_IDLE:	break;		/* fine */  case CMD_READ:  case CMD_WRITE:	/* Impossible, but not on PC's:  The controller does not respond. */	/* Limiting multisector I/O seems to help. */	if (wn->max_count > 8 * SECTOR_SIZE) {		wn->max_count = 8 * SECTOR_SIZE;	} else {		wn->max_count = SECTOR_SIZE;	}	/*FALL THROUGH*/  default:	/* Some other command. */	if (w_testing)  wn->state |= IGNORING;	/* Kick out this drive. */	else if (!w_silent) printf("%s: timeout on command %02x\n", w_name(), w_command);	w_need_reset();	wn->w_status = 0;  }}/*===========================================================================* *				w_reset					     * *===========================================================================*/PRIVATE int w_reset(){/* Issue a reset to the controller.  This is done after any catastrophe, * like the controller refusing to respond. */  int s;  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);  /* Strobe reset bit */  if ((s=sys_outb(wn->base_ctl + REG_CTL, CTL_RESET)) != OK)  	panic(w_name(),"Couldn't strobe reset bit",s);  tickdelay(DELAY_TICKS);  if ((s=sys_outb(wn->base_ctl + REG_CTL, 0)) != OK)  	panic(w_name(),"Couldn't strobe reset bit",s);  tickdelay(DELAY_TICKS);  /* Wait for controller ready */  if (!w_waitfor(STATUS_BSY, 0)) {	printf("%s: reset failed, drive busy\n", w_name());	return(ERR);  }  /* The error register should be checked now, but some drives mess it up. */  for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {	if (wn->base_cmd == w_wn->base_cmd) {		wn->state &= ~DEAF;  		if (w_wn->irq_need_ack) {		    	/* Make sure irq is actually enabled.. */	  		sys_irqenable(&w_wn->irq_hook_id);		}	}  }		  return(OK);}/*===========================================================================* *				w_intr_wait				     * *===========================================================================*/PRIVATE void w_intr_wait(){/* Wait for a task completion interrupt. */  message m;  if (w_wn->irq != NO_IRQ) {	/* Wait for an interrupt that sets w_status to "not busy". */	while (w_wn->w_status & (STATUS_ADMBSY|STATUS_BSY)) {		receive(ANY, &m);		/* expect HARD_INT message */		if (m.m_type == SYN_ALARM) { 	/* but check for timeout */		    w_timeout();		/* a.o. set w_status */		} else if (m.m_type == HARD_INT) {		    sys_inb(w_wn->base_cmd + REG_STATUS, &w_wn->w_status);		    ack_irqs(m.NOTIFY_ARG);		} else if (m.m_type == DEV_PING) {		    notify(m.m_source);	        } else {	        	printf("AT_WINI got unexpected message %d from %d\n",	        		m.m_type, m.m_source);	        }	}  } else {	/* Interrupt not yet allocated; use polling. */	(void) w_waitfor(STATUS_BSY, 0);  }}/*===========================================================================* *				at_intr_wait				     * *===========================================================================*/PRIVATE int at_intr_wait(){/* Wait for an interrupt, study the status bits and return error/success. */  int r;  int s,inbval;		/* read value with sys_inb */   w_intr_wait();  if ((w_wn->w_status & (STATUS_BSY | STATUS_WF | STATUS_ERR)) == 0) {	r = OK;  } else {  	if ((s=sys_inb(w_wn->base_cmd + REG_ERROR, &inbval)) != OK)  		panic(w_name(),"Couldn't read register",s);  	if ((w_wn->w_status & STATUS_ERR) && (inbval & ERROR_BB)) {  		r = ERR_BAD_SECTOR;	/* sector marked bad, retries won't help */  	} else {  		r = ERR;		/* any other error */  	}  }  w_wn->w_status |= STATUS_ADMBSY;	/* assume still busy with I/O */  return(r);}/*===========================================================================* *				w_waitfor				     * *===========================================================================*/PRIVATE int w_waitfor(mask, value)int mask;			/* status mask */int value;			/* required status */{/* Wait until controller is in the required state.  Return zero on timeout. * An alarm that set a timeout flag is used. TIMEOUT is in micros, we need * ticks. Disabling the alarm is not needed, because a static flag is used * and a leftover timeout cannot do any harm. */  clock_t t0, t1;  int s;  getuptime(&t0);  do {	if ((s=sys_inb(w_wn->base_cmd + REG_STATUS, &w_wn->w_status)) != OK)		panic(w_name(),"Couldn't read register",s);	if ((w_wn->w_status & mask) == value) {        	return 1;	}  } while ((s=getuptime(&t1)) == OK && (t1-t0) < timeout_ticks );  if (OK != s) printf("AT_WINI: warning, get_uptime failed: %d\n",s);  w_need_reset();			/* controller gone deaf */  return(0);}/*===========================================================================* *				w_geometry				     * *===========================================================================*/PRIVATE void w_geometry(entry)struct partition *entry;{  struct wini *wn = w_wn;  if (wn->state & ATAPI) {		/* Make up some numbers. */	entry->cylinders = div64u(wn->part[0].dv_size, SECTOR_SIZE) / (64*32);	entry->heads = 64;	entry->sectors = 32;  } else {				/* Return logical geometry. */	entry->cylinders = wn->lcylinders;	entry->heads = wn->lheads;	entry->sectors = wn->lsectors;  }}#if ENABLE_ATAPI/*===========================================================================* *				atapi_open				     * *===========================================================================*/PRIVATE int atapi_open(){/* Should load and lock the device and obtain its size.  For now just set the * size of the device to something big.  What is really needed is a generic * SCSI layer that does all this stuff for ATAPI and SCSI devices (kjb). (XXX) */  w_wn->part[0].dv_size = mul64u(800L*1024, 1024);  return(OK);}/*===========================================================================* *				atapi_close				     * *===========================================================================*/PRIVATE void atapi_close(){/* Should unlock the device.  For now do nothing.  (XXX) */}void sense_request(void){	int r, i;	static u8_t sense[100], packet[ATAPI_PACKETSIZE];	packet[0] = SCSI_SENSE;	packet[1] = 0;	packet[2] = 0;	packet[3] = 0;	packet[4] = SENSE_PACKETSIZE;	packet[5] = 0;	packet[7] = 0;	packet[8] = 0;	packet[9] = 0;	packet[10] = 0;	packet[11] = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -