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

📄 aha_scsi.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
FORWARD _PROTOTYPE( int s_do_ioctl, (struct driver *dp, message *m_ptr) );
FORWARD _PROTOTYPE( int scsi_simple, (int opcode, int count) );
FORWARD _PROTOTYPE( void group0, (void) );
FORWARD _PROTOTYPE( void group1, (void) );
FORWARD _PROTOTYPE( int scsi_command, (phys_bytes data, vir_bytes len) );
FORWARD _PROTOTYPE( void aha_command, (int outlen, byte *outptr,
						int inlen, byte *inptr) );
FORWARD _PROTOTYPE( int aha_reset, (void) );
FORWARD _PROTOTYPE( int s_handler, (int irq) );

FORWARD _PROTOTYPE( void h2b16, (big16 b, U16_t l) );
FORWARD _PROTOTYPE( void h2b24, (big24 b, u32_t l) );
FORWARD _PROTOTYPE( void h2b32, (big32 b, u32_t l) );
FORWARD _PROTOTYPE( u16_t b2h16, (big16 b) );
FORWARD _PROTOTYPE( u32_t b2h24, (big24 b) );
FORWARD _PROTOTYPE( u32_t b2h32, (big32 b) );


#if AHA_DEBUG & 2
FORWARD _PROTOTYPE( void errordump, (void) );
#else
#define errordump()
#endif

#if AHA_DEBUG & 4
FORWARD _PROTOTYPE( void show_req, (void) );
#else
#define show_req()
#endif

#if AHA_DEBUG & 8
FORWARD _PROTOTYPE( void dump_scsi_cmd, (void) );
#else
#define dump_scsi_cmd()
#endif

FORWARD _PROTOTYPE( void s_geometry, (struct partition *entry));


/* Entry points to this driver. */
PRIVATE struct driver s_dtab = {
  s_name,	/* current device's name */
  s_do_open,	/* open or mount request, initialize device */
  s_do_close,	/* release device */
  s_do_ioctl,	/* tape and partition ioctls */
  s_prepare,	/* prepare for I/O on a given minor device */
  s_schedule,	/* precompute SCSI transfer parameters, etc. */
  s_finish,	/* do the I/O */
  nop_cleanup,	/* no cleanup needed */
  s_geometry	/* tell the geometry of the disk */
};


/*===========================================================================*
 *				aha_scsi_task				     *
 *===========================================================================*/
PUBLIC void aha_scsi_task()
{
/* Set target and logical unit numbers, then call the generic main loop. */
  int i;
  struct scsi *sp;
  long v;
  char *name;
  static char fmt[] = "d,d";

  for (i = 0; i < MAX_DEVICES; i++) {
	(void) s_prepare(i * DEV_PER_DRIVE);
	sp = s_sp;

	/* Look into the environment for special parameters. */
	name = s_name();

	v = i;
	(void) env_parse(name, fmt, 0, &v, 0L, 7L);
	sp->targ = v;

	v = 0;
	(void) env_parse(name, fmt, 1, &v, 0L, 7L);
	sp->lun = v;
  }
  driver_task(&s_dtab);
}


/*===========================================================================*
 *				s_prepare				     *
 *===========================================================================*/
PRIVATE struct device *s_prepare(device)
int device;
{
/* Prepare for I/O on a device. */

  rq->count = 0;	/* no requests as yet */
  s_must = TRUE;	/* the first transfers must be done */
  s_buf_blk = -1;	/* invalidate s_buf_blk */

  if (device < NR_DISKDEVS) {			/* sd0, sd1, ... */
	s_type = TYPE_SD;
	s_sp = &scsi[device / DEV_PER_DRIVE];
	s_dv = &s_sp->part[device % DEV_PER_DRIVE];
  } else
  if ((unsigned) (device - MINOR_hd1a) < NR_SUBDEVS) {	/* sd1a, sd1b, ... */
	device -= MINOR_hd1a;
	s_type = TYPE_SD;
	s_sp = &scsi[device / SUB_PER_DRIVE];
	s_dv = &s_sp->subpart[device % SUB_PER_DRIVE];
  } else
  if ((unsigned) (device - MINOR_st0) < NR_TAPEDEVS) {	/* nrst0, rst0, ... */
	device -= MINOR_st0;
	s_type = device & 1 ? TYPE_RST : TYPE_NRST;
	s_sp = &scsi[device >> 1];
	s_dv = &s_sp->dummypart;
  } else {
	return(NIL_DEV);
  }

  return(s_dv);
}


/*===========================================================================*
 *				s_name					     *
 *===========================================================================*/
PRIVATE char *s_name()
{
/* Return a name for the current device. */
  static char name[] = "sd35";
  int n = (s_sp - scsi);

  switch (s_type) {
  case TYPE_SD:			/* Disk device: sd* */
	name[1] = 'd';
	n *= DEV_PER_DRIVE;
	break;
  case TYPE_RST:		/* Tape device: st* */
  case TYPE_NRST:
	name[1] = 't';
	break;
  }
  if (n < 10) {
	name[2] = '0' + n;
	name[3] = 0;
  } else {
	name[2] = '0' + n / 10;
	name[3] = '0' + n % 10;
  }
  return name;
}


/*===========================================================================*
 *				s_do_open				     *
 *===========================================================================*/
PRIVATE int s_do_open(dp, m_ptr)
struct driver *dp;
message *m_ptr;
{
  struct scsi *sp;
  int r;

  if (aha_irq == 0 && !aha_reset()) return(EIO); /* no controller, forget it */

  if (s_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  sp = s_sp;

  if ((r = scsi_probe()) != OK) return(r);

  if (sp->state & S_RDONLY && m_ptr->COUNT & W_BIT) return(EACCES);

  switch (sp->devtype) {
  case SCSI_DEVDISK:
  case SCSI_DEVWORM:
  case SCSI_DEVCDROM:
  case SCSI_DEVOPTICAL:
	/* Read partition tables on first open. */
	if (sp->open_ct == 0) {
		partition(&s_dtab, (int) (sp-scsi) * DEV_PER_DRIVE, P_PRIMARY);
	}
	break;
  case SCSI_DEVTAPE:
	/* Make sure tape is not already open. */
	if (sp->open_ct > 0) return(EBUSY);

	sp->open_mode = m_ptr->COUNT;
	/* If open(..., O_WRONLY) then write a filemark on close even if no
	 * write is done.
	 */
	sp->need_eof = ((sp->open_mode & (R_BIT|W_BIT)) == W_BIT);
	break;
  }
  sp->open_ct++;
  return(OK);
}


/*===========================================================================*
 *				scsi_probe				     *
 *===========================================================================*/
PRIVATE int scsi_probe()
{
/* See if a device exists and if it is ready. */
  struct scsi *sp = s_sp;
  sense_t *sense;
  int r, key;

  /* Something out there? */
  if ((r = scsi_sense()) != OK) {
	if (sp->state & S_PRESENT) {
		printf("%s: offline\n", s_name());
		sp->state = 0;
	}
	return(r);
  }

  if (!(sp->state & S_PRESENT)) {
	/* First contact with a new device, what type is it? */

	if ((r = scsi_inquiry()) != OK) return(r);

	sp->devtype = inqdata.devtype;
  }

  if (!(sp->state & S_READY)) {
	/* If it's a disk: start it, if it's a tape: load it. */
	(void) scsi_simple(SCSI_STRTSTP, 1);
  }

  /* See if the unit is ready for I/O.  A disk may be spinning up, a
   * floppy or tape drive may be empty.
   */
  while ((key = scsi_simple(SCSI_UNITRDY, 0)) != SENSE_NO_SENSE) {
	/* Not ready, why? */

	sp->state &= ~S_READY;

	switch (key) {
	case SENSE_UNIT_ATT:
		/* A media change or something, try again. */
		break;
	case SENSE_NOT_READY:
		/* Look at the additional sense data to see why it isn't
		 * ready.
		 */
		sense = &ccb_sense(rq);
		switch ((sense->add_code << 8) | sense->add_qual) {
		case 0x0401:
			/* "It is becoming ready."  Fine, we wait. */
			milli_delay(1000);
			break;
		case 0x0402:
			/* "Initialization command required."  So we tell it
			 * to spin up.
			 */
			if (scsi_simple(SCSI_STRTSTP, 1) != SENSE_NO_SENSE)
				return(EIO);
			break;
		case 0x0403:
			/* "Manual intervention required." */
		case 0x3A00:
			/* "No media present." */
			printf("%s: no media loaded\n", s_name());
			return(EIO);
		default:
			/* For some reason it is not usable. */
			printf("%s: not ready\n", s_name());
			return(EIO);
		}
		break;
	default:
		/* The device is in some odd state.  */
		if (key != SENSE_NOT_READY) {
			printf("%s: hardware error\n", s_name());
			return(EIO);
		}
	}
  }

  if (!(sp->state & S_PRESENT)) {
	/* Do the inquiry again, the message may have changed. */
	if (scsi_inquiry() != OK) return(EIO);

	/* Tell what kind of device it is we have found. */

	printf("%s: %-7s %.48s\n",
		s_name(),
		inqdata.devtype > SCSI_DEVMAX ? "UNKNOWN"
				: scsi_devstr[inqdata.devtype],
		inqdata.vendor /* + product + revision + extra */);
  }

  if (!(sp->state & S_READY)) {
	/* Get the geometry, limits, etc. */

	switch (sp->devtype) {
	case SCSI_DEVDISK:
	case SCSI_DEVWORM:
	case SCSI_DEVCDROM:
	case SCSI_DEVOPTICAL:
		if (scsi_ndisk() != OK) return(EIO);
		break;
	case SCSI_DEVTAPE:
		if (scsi_ntape() != OK) return(EIO);
		break;
	default:
		printf("%s: unsupported\n", s_name());
		return(EIO);
	}
  }
  return(OK);
}


/*===========================================================================*
 *				scsi_sense				     *
 *===========================================================================*/
PRIVATE int scsi_sense()
{
  int key;
  sense_t *sense = (sense_t *) tmp_buf;

  /* Do a request sense to find out if a target exists or to check out
   * a unit attention condition.
   */
  key = scsi_simple(SCSI_REQSENSE, sizeof(sense_t));

  if (rq->ccb.hastat == HST_TIMEOUT) return(ENXIO);	/* nothing there */
  if (rq->ccb.hastat != 0) return(EIO);		/* something very bad */

  /* There is something out there for sure. */
  if (key == SENSE_UNIT_ATT || sense_key(sense->key) == SENSE_UNIT_ATT) {
	/* Device is in a "look at me" state, probably changed media. */
	s_sp->state &= ~S_READY;
  }
  return(OK);
}


/*===========================================================================*
 *				scsi_inquiry				     *
 *===========================================================================*/
PRIVATE int scsi_inquiry()
{
  /* Prefill with nulls. */
  memset(tmp_buf, '\0', sizeof(inquiry_t));

  /* Do a SCSI inquiry. */
  if (scsi_simple(SCSI_INQUIRY, sizeof(inquiry_t)) != SENSE_NO_SENSE)
	return(EIO);
  inqdata = * (inquiry_t *) tmp_buf;

  if (inqdata.len == 0) {
	/* The device doesn't return meaningful text fields. */
	strcpy(inqdata.vendor, "(unknown)");
  }

  /* The top three bits of devtype must be zero for the lun to exist. */
  if ((inqdata.devtype & 0xE0) != 0) return(ENXIO);

  return(OK);
}


/*===========================================================================*
 *				scsi_ndisk				     *
 *===========================================================================*/
PRIVATE int scsi_ndisk()
{
/* Gather disk data, capacity and block size. */

  struct scsi *sp = s_sp;
  unsigned long capacity = -1, block_size = SECTOR_SIZE;
  byte *buf = tmp_buf;

  /* Minor device type must be for a disk. */
  if (s_type != TYPE_SD) return(EIO);

  if (sp->devtype == SCSI_DEVCDROM) {
	/* Read-only by definition. */
	sp->state |= S_RDONLY;
  } else {
	/* SCSI modesense to find out if the disk is write protected. */
	if (scsi_simple(SCSI_MDSENSE, 255) != SENSE_NO_SENSE) return(EIO);

	/* Write protected? */
	sp->state &= ~S_RDONLY;
	if (buf[2] & 0x80) sp->state |= S_RDONLY;

	/* Don't write a worm disk, not wise at the moment. */
	if (sp->devtype == SCSI_DEVWORM) sp->state |= S_RDONLY;
  }

  /* Get drive capacity and block size. */
  group1();
  rq->ccb.opcode = CCB_INIT;
  ccb_cmd1(rq).scsi_op = SCSI_CAPACITY;

  if (scsi_command(tmp_phys, 8) == SENSE_NO_SENSE) {
	capacity = b2h32(buf + 0) + 1;
	block_size = b2h32(buf + 4);
	printf("%s: capacity %lu x %lu bytes\n",
					s_name(), capacity, block_size);
  } else {
	printf("%s: unknown capacity\n", s_name());
  }

  /* We do not believe block sizes over 4 kb. */
  if (block_size > 4096) {
	printf("%s: can't handle %lu byte blocks\n", s_name(), block_size);
	return(EIO);
  }

  sp->block_size = block_size;
#if _WORD_SIZE > 2
  /* Keep it within reach of a group 0 command. */
  sp->count_max = 0x100 * block_size;
#else
  sp->count_max = block_size > UINT_MAX/0x100 ? UINT_MAX : 0x100 * block_size;
#endif

  /* The fun ends at 4GB. */
  if (capacity > ((unsigned long) -1) / block_size)
	sp->part[0].dv_size = -1;
  else
	sp->part[0].dv_size = capacity * block_size;

  /* Finally we recognize its existence. */
  sp->state |= S_PRESENT|S_READY;

  return(OK);
}


/*===========================================================================*
 *				scsi_ntape				     *

⌨️ 快捷键说明

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