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

📄 at_wini.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	cmd.sector  = 0;
	cmd.cyl_lo  = 0;
	cmd.cyl_hi  = 0;
	cmd.ldh     = w_wn->ldhpref;
	cmd.command = CMD_RECALIBRATE;

	if (com_simple(&cmd) != OK) return(ERR);
  }

  wn->state |= INITIALIZED;
  return(OK);
}


/*===========================================================================*
 *				w_schedule				     *
 *===========================================================================*/
PRIVATE int w_schedule(proc_nr, iop)
int proc_nr;			/* process doing the request */
struct iorequest_s *iop;	/* pointer to read or write request */
{
/* Gather I/O requests on consecutive blocks so they may be read/written
 * in one controller command.  (There is enough time to compute the next
 * consecutive request while an unwanted block passes by.)
 */
  struct wini *wn = w_wn;
  int r, opcode;
  unsigned long pos;
  unsigned nbytes, count;
  unsigned long block;
  phys_bytes user_phys;

  /* This many bytes to read/write */
  nbytes = iop->io_nbytes;
  if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);

  /* From/to this position on the device */
  pos = iop->io_position;
  if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);

  /* To/from this user address */
  user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
  if (user_phys == 0) return(iop->io_nbytes = EINVAL);

  /* Read or write? */
  opcode = iop->io_request & ~OPTIONAL_IO;

  /* Which block on disk and how close to EOF? */
  if (pos >= w_dv->dv_size) return(OK);		/* At EOF */
  if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
  block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;

  if (w_count > 0 && block != w_nextblock) {
	/* This new request can't be chained to the job being built */
	if ((r = w_finish()) != OK) return(r);
  }

  /* The next consecutive block */
  w_nextblock = block + (nbytes >> SECTOR_SHIFT);

  /* While there are "unscheduled" bytes in the request: */
  do {
	count = nbytes;

	if (w_count == wn->max_count) {
		/* The drive can't do more then max_count at once */
		if ((r = w_finish()) != OK) return(r);
	}

	if (w_count + count > wn->max_count)
		count = wn->max_count - w_count;

	if (w_count == 0) {
		/* The first request in a row, initialize. */
		w_opcode = opcode;
		w_tp = wtrans;
	}

	/* Store I/O parameters */
	w_tp->iop = iop;
	w_tp->block = block;
	w_tp->count = count;
	w_tp->phys = user_phys;

	/* Update counters */
	w_tp++;
	w_count += count;
	block += count >> SECTOR_SHIFT;
	user_phys += count;
	nbytes -= count;
  } while (nbytes > 0);

  return(OK);
}


/*===========================================================================*
 *				w_finish				     *
 *===========================================================================*/
PRIVATE int w_finish()
{
/* Carry out the I/O requests gathered in wtrans[]. */

  struct trans *tp = wtrans;
  struct wini *wn = w_wn;
  int r, errors;
  struct command cmd;
  unsigned cylinder, head, sector, secspcyl;

  if (w_count == 0) return(OK);	/* Spurious finish. */

  r = ERR;	/* Trigger the first com_out */
  errors = 0;

  do {
	if (r != OK) {
		/* The controller must be (re)programmed. */

		/* First check to see if a reinitialization is needed. */
		if (!(wn->state & INITIALIZED) && w_specify() != OK)
			return(tp->iop->io_nbytes = EIO);

		/* Tell the controller to transfer w_count bytes */
		cmd.precomp = wn->precomp;
		cmd.count   = (w_count >> SECTOR_SHIFT) & BYTE;
		if (wn->ldhpref & LDH_LBA) {
			cmd.sector  = (tp->block >>  0) & 0xFF;
			cmd.cyl_lo  = (tp->block >>  8) & 0xFF;
			cmd.cyl_hi  = (tp->block >> 16) & 0xFF;
			cmd.ldh     = wn->ldhpref | ((tp->block >> 24) & 0xF);
		} else {
			secspcyl = wn->pheads * wn->psectors;
			cylinder = tp->block / secspcyl;
			head = (tp->block % secspcyl) / wn->psectors;
			sector = tp->block % wn->psectors;
			cmd.sector  = sector + 1;
			cmd.cyl_lo  = cylinder & BYTE;
			cmd.cyl_hi  = (cylinder >> 8) & BYTE;
			cmd.ldh     = wn->ldhpref | head;
		}
		cmd.command = w_opcode == DEV_WRITE ? CMD_WRITE : CMD_READ;

		if ((r = com_out(&cmd)) != OK) {
			if (++errors == MAX_ERRORS) {
				w_command = CMD_IDLE;
				return(tp->iop->io_nbytes = EIO);
			}
			continue;	/* Retry */
		}
	}

	/* 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 (w_opcode == DEV_READ) {
		if ((r = w_intr_wait()) == OK) {
			/* Copy data from the device's buffer to user space. */

			port_read(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);

			tp->phys += SECTOR_SIZE;
			tp->iop->io_nbytes -= SECTOR_SIZE;
			w_count -= SECTOR_SIZE;
			if ((tp->count -= SECTOR_SIZE) == 0) tp++;
		} else {
			/* Any faulty data? */
			if (w_status & STATUS_DRQ) {
				port_read(wn->base + REG_DATA, tmp_phys,
								SECTOR_SIZE);
			}
		}
	} else {
		/* Wait for data requested. */
		if (!waitfor(STATUS_DRQ, STATUS_DRQ)) {
			r = ERR;
		} else {
			/* Fill the buffer of the drive. */

			port_write(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);
			r = w_intr_wait();
		}

		if (r == OK) {
			/* Book the bytes successfully written. */

			tp->phys += SECTOR_SIZE;
			tp->iop->io_nbytes -= SECTOR_SIZE;
			w_count -= SECTOR_SIZE;
			if ((tp->count -= SECTOR_SIZE) == 0) tp++;
		}
	}

	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(tp->iop->io_nbytes = EIO);
		}

		/* Reset if halfway, but bail out if optional I/O. */
		if (errors == MAX_ERRORS / 2) {
			w_need_reset();
			if (tp->iop->io_request & OPTIONAL_IO) {
				w_command = CMD_IDLE;
				return(tp->iop->io_nbytes = EIO);
			}
		}
		continue;	/* Retry */
	}
	errors = 0;
  } while (w_count > 0);

  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 = wn->base;

  if (!waitfor(STATUS_BSY, 0)) {
	printf("%s: controller not ready\n", w_name());
	return(ERR);
  }

  /* Select drive. */
  out_byte(base + REG_LDH, cmd->ldh);

  if (!waitfor(STATUS_BSY, 0)) {
	printf("%s: drive not ready\n", w_name());
	return(ERR);
  }

  /* Schedule a wakeup call, some controllers are flaky. */
  clock_mess(WAKEUP, w_timeout);

  out_byte(base + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
  out_byte(base + REG_PRECOMP, cmd->precomp);
  out_byte(base + REG_COUNT, cmd->count);
  out_byte(base + REG_SECTOR, cmd->sector);
  out_byte(base + REG_CYL_LO, cmd->cyl_lo);
  out_byte(base + REG_CYL_HI, cmd->cyl_hi);
  lock();
  out_byte(base + REG_COMMAND, cmd->command);
  w_command = cmd->command;
  w_status = STATUS_BSY;
  unlock();
  return(OK);
}


/*===========================================================================*
 *				w_need_reset				     *
 *===========================================================================*/
PRIVATE void w_need_reset()
{
/* The controller needs to be reset. */
  struct wini *wn;

  for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
	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--;
  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 ((r = com_out(cmd)) == OK) r = w_intr_wait();
  w_command = CMD_IDLE;
  return(r);
}


/*===========================================================================*
 *				w_timeout				     *
 *===========================================================================*/
PRIVATE void w_timeout()
{
  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. */
	printf("%s: timeout on command %02x\n", w_name(), w_command);
	w_need_reset();
	w_status = 0;
	interrupt(WINCHESTER);
  }
}


/*===========================================================================*
 *				w_reset					     *
 *===========================================================================*/
PRIVATE int w_reset()
{
/* Issue a reset to the controller.  This is done after any catastrophe,
 * like the controller refusing to respond.
 */

  struct wini *wn;
  int err;

  /* Wait for any internal drive recovery. */
  milli_delay(RECOVERYTIME);

  /* Strobe reset bit */
  out_byte(w_wn->base + REG_CTL, CTL_RESET);
  milli_delay(1);
  out_byte(w_wn->base + REG_CTL, 0);
  milli_delay(1);

  /* Wait for controller ready */
  if (!w_waitfor(STATUS_BSY | STATUS_RDY, STATUS_RDY)) {
	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 == w_wn->base) wn->state &= ~DEAF;
  }
  return(OK);
}


/*============================================================================*
 *				w_intr_wait				      *
 *============================================================================*/
PRIVATE int w_intr_wait()
{
/* Wait for a task completion interrupt and return results. */

  message mess;
  int r;

  /* Wait for an interrupt that sets w_status to "not busy". */
  while (w_status & STATUS_BSY) receive(HARDWARE, &mess);

  /* Check status. */
  lock();
  if ((w_status & (STATUS_BSY | STATUS_RDY | STATUS_WF | STATUS_ERR))
							== STATUS_RDY) {
	r = OK;
	w_status |= STATUS_BSY;	/* assume still busy with I/O */
  } else
  if ((w_status & STATUS_ERR) && (in_byte(w_wn->base + REG_ERROR) & ERROR_BB)) {
  	r = ERR_BAD_SECTOR;	/* sector marked bad, retries won't help */
  } else {
  	r = ERR;		/* any other error */
  }
  unlock();
  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. */

  struct milli_state ms;

  milli_start(&ms);
  do {
       if ((in_byte(w_wn->base + REG_STATUS) & mask) == value) return 1;
  } while (milli_elapsed(&ms) < TIMEOUT);

  w_need_reset();	/* Controller gone deaf. */
  return(0);
}


/*==========================================================================*
 *				w_handler				    *
 *==========================================================================*/
PRIVATE int w_handler(irq)
int irq;
{
/* Disk interrupt, send message to winchester task and reenable interrupts. */

  w_status = in_byte(w_wn->base + REG_STATUS);	/* acknowledge interrupt */
  interrupt(WINCHESTER);
  return 1;
}


/*============================================================================*
 *				w_geometry				      *
 *============================================================================*/
PRIVATE void w_geometry(entry)
struct partition *entry;
{
  entry->cylinders = w_wn->lcylinders;
  entry->heads = w_wn->lheads;
  entry->sectors = w_wn->lsectors;
}
#endif /* ENABLE_AT_WINI */

⌨️ 快捷键说明

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