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

📄 aha_scsi.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}

	/* Check sense data, report error if interesting. */
	if (rq->ccb.tarstat == TST_CHECK) {
		if ((sense->errc & 0x7E) == 0x70) {
			/* Standard SCSI error. */
			key = sense->key;
		} else {
			/* Blame the vendor for any other nonsense. */
			key = SENSE_VENDOR;
		}
	} else {
		if (rq->ccb.tarstat == TST_LUNBUSY) {
			/* Logical unit is too busy to react... */
			key = SENSE_NOT_READY;
		} else {
			/* The adapter shoudn't do this... */
			key = SENSE_HARDWARE;
		}
		memset((void *) sense, 0, sizeof(sense_t));
	}

	if (sense_serious(sense_key(key))) {
		/* Something bad happened. */
		printf("%s: error on command 0x%02x, ", s_name(),
							rq->ccb.cmd[0]);
		if (rq->ccb.tarstat != TST_CHECK) {
			printf("target status 0x%02x\n", rq->ccb.tarstat);
		} else {
			printf("sense key 0x%02x (%s), additional 0x%02x%02x\n",
				sense->key,
				str_scsi_sense[sense_key(key)],
				sense->add_code, sense->add_qual);
		}
		errordump();
	}

	if (sp->devtype == SCSI_DEVTAPE) {
		/* Store details of tape error. */
		sp->tstat.mt_dsreg = DS_ERR;
		sp->tstat.mt_erreg = key;
		sp->tstat.mt_resid = b2h32(sense->info);
	}

	/* Keep only the ILI, EOM and EOF bits of key 0. */
	if (sense_key(key) != SENSE_NO_SENSE) key = sense_key(key);

	return(key);
  }
  return(SENSE_NO_SENSE);
}


/*===========================================================================*
 *				aha_command				     *
 *===========================================================================*/
PRIVATE void aha_command(outlen, outptr, inlen, inptr)
int outlen, inlen;
byte *outptr, *inptr;
{
  /* Send a low level command to the host adapter. */
  int i;

  /* Send command bytes. */
  for (i = 0; i < outlen; i++) {
	while (in_byte(AHA_STATREG) & AHA_CDF) {}	/* !! timeout */
	out_byte(AHA_DATAREG, *outptr++);
  }

  /* Receive data bytes. */
  for (i = 0; i < inlen; i++) {
	while (!(in_byte(AHA_STATREG) & AHA_DF)
		&& !(in_byte(AHA_INTRREG) & AHA_HACC)) {}  /* !! timeout */
	*inptr++ = in_byte(AHA_DATAREG);
  }

  /* Wait for command completion. */
  while (!(in_byte(AHA_INTRREG) & AHA_HACC)) {}	/* !! timeout */
  out_byte(AHA_CNTLREG, AHA_IRST);	/* clear interrupt */
  if (aha_irq != 0) enable_irq(aha_irq);

  /* !! should check status register here for invalid command */
}


/*===========================================================================*
 *				aha_reset				     *
 *===========================================================================*/
PRIVATE int aha_reset()
{
  int stat;
  int irq, bus_on, bus_off, tr_speed;
  unsigned sg_max;
  long v;
  static char aha0_env[] = "AHA0", aha_fmt[] = "x:d:d:x";
  byte cmd[5], haidata[4], getcdata[3], extbios[2];
  struct milli_state ms;

  /* Get the configuration info from the environment. */
  v = AHA_BASEREG;
  if (env_parse(aha0_env, aha_fmt, 0, &v, 0x000L, 0x3FFL) == EP_OFF) return 0;
  aha_basereg = v;

  v = 15;
  (void) env_parse(aha0_env, aha_fmt, 1, &v, 2L, 15L);
  bus_on = v;

  v = 1;
  (void) env_parse(aha0_env, aha_fmt, 2, &v, 1L, 64L);
  bus_off = v;

  v = 0x00;
  (void) env_parse(aha0_env, aha_fmt, 3, &v, 0x00L, 0xFFL);
  tr_speed = v;

  /* Reset controller, wait for self test to complete. */
  out_byte(AHA_CNTLREG, AHA_HRST);
  milli_start(&ms);
  while ((stat = in_byte(AHA_STATREG)) & AHA_STST) {
	if (milli_elapsed(&ms) >= AHA_TIMEOUT) {
		printf("aha0: AHA154x controller not responding\n");
		return(0);
	}
  }

  /* Check for self-test failure. */
  if ((stat & (AHA_DIAGF | AHA_INIT | AHA_IDLE | AHA_CDF | AHA_DF))
						!= (AHA_INIT | AHA_IDLE)) {
	printf("aha0: AHA154x controller failed self-test\n");
	return(0);
  }

  /* !! maybe a santity check here: make sure IDLE and INIT are set? */

  /* Get information about controller type and configuration. */
  cmd[0] = AHACOM_HAINQUIRY;
  aha_command(1, cmd, 4, haidata);

  cmd[0] = AHACOM_GETCONFIG;
  aha_command(1, cmd, 3, getcdata);

  /* First inquiry byte tells what type of board. */
  aha_model = haidata[0];

  /* Unlock the 1540C or 1540CF's mailbox interface.  (This is to keep old
   * drivers from using the adapter if extended features are enabled.)
   */
  if (aha_model >= AHA1540C) {
	cmd[0] = AHACOM_EXTBIOS;	/* get extended BIOS information */
	aha_command(1, cmd, 2, extbios);
	if (extbios[1] != 0) {
		/* Mailbox interface is locked, so unlock it. */
		cmd[0] = AHACOM_MBOX_ENABLE;
		cmd[1] = 0;		/* bit 0 = 0 (enable mailbox) */
		cmd[2] = extbios[1];	/* lock code to unlock mailbox */
		aha_command(3, cmd, 0, 0);
	}
  }

  /* The maximum scatter/gather DMA list length depends on the board model. */
  sg_max = 16;
  if (aha_model == AHA1540) sg_max = 1;		/* 1540 has no s/g */
  if (aha_model >= AHA1540C) sg_max = 255;	/* 1540C has plenty */

  /* Set up the DMA channel. */
  switch (getcdata[0]) {
  case 0x80:		/* channel 7 */
	out_byte(0xD6, 0xC3);
	out_byte(0xD4, 0x03);
	break;
  case 0x40:		/* channel 6 */
	out_byte(0xD6, 0xC2);
	out_byte(0xD4, 0x02);
	break;
  case 0x20:		/* channel 5 */
	out_byte(0xD6, 0xC1);
	out_byte(0xD4, 0x01);
	break;
  case 0x01:		/* channel 0 */
	out_byte(0x0B, 0x0C);
	out_byte(0x0A, 0x00);
	break;
  default:
	printf("aha0: AHA154x: strange DMA channel\n");
	return(0);
  }

  /* Get the configured IRQ. */
  switch (getcdata[1]) {
  case 0x40:	irq = 15;	break;
  case 0x20:	irq = 14;	break;
  case 0x08:	irq = 12;	break;
  case 0x04:	irq = 11;	break;
  case 0x02:	irq = 10;	break;
  case 0x01:	irq =  9;	break;
  default:
	printf("aha0: strange IRQ setting\n");
	return(0);
  }

  /* Enable interrupts on the given irq. */
  put_irq_handler(irq, s_handler);
  aha_irq = irq;
  enable_irq(irq);

  /* Initialize request related data: Command Control Block, mailboxes.
   * (We want to have the mailboxes initialized early, because the 1540C
   * wants to know it now.)
   */

  /* Init ccb. */
  rq->ccb.senselen = CCB_SENSEREQ;	/* always want sense info */
  h2b24(rq->ccb.linkptr, 0L);		/* never link commands */
  rq->ccb.linkid = 0;
  rq->ccb.reserved[0] = 0;
  rq->ccb.reserved[1] = 0;

  /* Scatter/gather maximum. */
  rq->dmalimit = rq->dmalist + (sg_max < NR_IOREQS ? sg_max : NR_IOREQS);

  /* Outgoing mailbox. */
  mailbox[0].status = AHA_MBOXFREE;
  h2b24(mailbox[0].ccbptr, vir2phys(&rq->ccb));

  /* Incoming mailbox. */
  mailbox[1].status = AHA_MBOXFREE;
  /* mailbox[1].ccbptr filled by adapter after command execution. */

  /* Tell controller where the mailboxes are and how many. */
  cmd[0] = AHACOM_INITBOX;
  cmd[1] = 1;
  h2b24(cmd + 2, vir2phys(mailbox));
  aha_command(5, cmd, 0, 0);

  /* !! maybe sanity check: check status reg for initialization success */

  /* Set bus on, bus off and transfer speed. */
  cmd[0] = AHACOM_BUSON;
  cmd[1] = bus_on;
  aha_command(2, cmd, 0, 0);

  cmd[0] = AHACOM_BUSOFF;
  cmd[1] = bus_off;
  aha_command(2, cmd, 0, 0);

  cmd[0] = AHACOM_SPEED;
  cmd[1] = tr_speed;
  aha_command(2, cmd, 0, 0);

  /* Set SCSI selection timeout. */
  cmd[0] = AHACOM_SETIMEOUT;
  cmd[1] = SCSI_TIMEOUT != 0;		/* timeouts on/off */
  cmd[2] = 0;				/* reserved */
  cmd[3] = SCSI_TIMEOUT / 256;		/* MSB */
  cmd[4] = SCSI_TIMEOUT % 256;		/* LSB */
  aha_command(5, cmd, 0, 0);

  return(1);
}


/*===========================================================================*
 *				s_handler				     *
 *===========================================================================*/
PRIVATE int s_handler(irq)
int irq;
{
/* Host adapter interrupt, send message to SCSI task and reenable interrupts. */

  if (in_byte(AHA_INTRREG) & AHA_HACC) {
	/* Simple commands are polled. */
	return 0;
  } else {
	out_byte(AHA_CNTLREG, AHA_IRST);	/* clear interrupt */
	interrupt(SCSI);
	return 1;
  }
}


/*===========================================================================*
 *				h2b16					     *
 *===========================================================================*/
PRIVATE void h2b16(b, h)
big16 b;
U16_t h;
{
/* Host byte order to Big Endian conversion. */
  b[0] = h >> 8;
  b[1] = h >> 0;
}


/*===========================================================================*
 *				h2b24					     *
 *===========================================================================*/
PRIVATE void h2b24(b, h)
big24 b;
u32_t h;
{
  b[0] = h >> 16;
  b[1] = h >>  8;
  b[2] = h >>  0;
}


/*===========================================================================*
 *				h2b32					     *
 *===========================================================================*/
PRIVATE void h2b32(b, h)
big32 b;
u32_t h;
{
  b[0] = h >> 24;
  b[1] = h >> 16;
  b[2] = h >>  8;
  b[3] = h >>  0;
}


/*===========================================================================*
 *				b2h16					     *
 *===========================================================================*/
PRIVATE u16_t b2h16(b)
big16 b;
{
  return  ((u16_t) b[0] << 8)
	| ((u16_t) b[1] << 0);
}


/*===========================================================================*
 *				b2h24					     *
 *===========================================================================*/
PRIVATE u32_t b2h24(b)
big24 b;
{
  return  ((u32_t) b[0] << 16)
	| ((u32_t) b[1] <<  8)
	| ((u32_t) b[2] <<  0);
}


/*===========================================================================*
 *				b2h32					     *
 *===========================================================================*/
PRIVATE u32_t b2h32(b)
big32 b;
{
  return  ((u32_t) b[0] << 24)
	| ((u32_t) b[1] << 16)
	| ((u32_t) b[2] <<  8)
	| ((u32_t) b[3] <<  0);
}


#if AHA_DEBUG & 2
/*===========================================================================*
 *				errordump				     *
 *===========================================================================*/
PRIVATE void errordump()
{
  int i;

  printf("aha ccb dump:");
  for (i = 0; i < sizeof(rq->ccb); i++) {
	if (i % 26 == 0) printf("\n");
	printf(" %02x", ((byte *) &rq->ccb)[i]);
  }
  printf("\n");
}
#endif /* AHA_DEBUG & 2 */


#if AHA_DEBUG & 4
/*===========================================================================*
 *				show_req				     *
 *===========================================================================*/
PRIVATE void show_req()
{
  struct iorequest_s **iopp;
  dma_t *dmap;
  unsigned count, nbytes, len;

  iopp = rq->iov;
  dmap = rq->dmalist;
  count = rq->count;
  nbytes = 0;

  printf("%lu:%u", rq->pos, count);

  while (count > 0) {
	if (iopp == rq->iov || *iopp != iopp[-1])
		nbytes = (*iopp)->io_nbytes;

	printf(" (%u,%lx,%u)", nbytes, b2h24(dmap->dataptr),
					len = b2h24(dmap->datalen));
	dmap++;
	iopp++;
	count -= len;
	nbytes -= len;
  }
  if (nbytes > 0) printf(" ...(%u)", nbytes);
  printf("\n");
}
#endif /* AHA_DEBUG & 4 */


#if AHA_DEBUG & 8
/*===========================================================================*
 *				dump_scsi_cmd				     *
 *===========================================================================*/
PRIVATE void dump_scsi_cmd()
{
  int i;

  printf("scsi cmd:");
  for (i = 0; i < rq->ccb.cmdlen; i++) printf(" %02x", rq->ccb.cmd[i]);
  printf("\n");
}
#endif /* AHA_DEBUG & 8 */


/*============================================================================*
 *				s_geometry				      *
 *============================================================================*/
PRIVATE void s_geometry(entry)
struct partition *entry;
{
/* The geometry of a SCSI drive is a complete fake, the Adaptec onboard BIOS
 * makes the drive look like a regular drive on the outside.  A DO

⌨️ 快捷键说明

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