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

📄 aha_scsi.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
  sp->at_eof = FALSE;

  /* Write filemark if writes have been done. */
  if (sp->need_eof && sp->tstat.mt_dsreg != DS_ERR) {
	if (scsi_simple(SCSI_WREOF, 1) != SENSE_NO_SENSE) {
		printf("%s: failed to add filemark\n", s_name());
	} else {
		sp->tstat.mt_dsreg = DS_OK;
		sp->tstat.mt_blkno = 0;
		sp->tstat.mt_fileno++;
	}
  }

  /* Rewind if rewind device. */
  if (s_type == TYPE_RST) {
	if (scsi_simple(SCSI_REWIND, 1) != SENSE_NO_SENSE) {
		printf("%s: failed to rewind\n", s_name());
	} else {
		sp->tstat.mt_dsreg = DS_OK;
		sp->tstat.mt_blkno = 0;
		sp->tstat.mt_fileno = 0;
	}
  }
  return(OK);
}


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

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

  /* Ioctls are device specific. */
  switch (sp->devtype) {
  case SCSI_DEVDISK:
  case SCSI_DEVWORM:
  case SCSI_DEVCDROM:
  case SCSI_DEVOPTICAL:
	if (m_ptr->REQUEST == DIOCEJECT) {
		/* Eject disk. */
		if (sp->open_ct > 1) return(EBUSY);

		/* Send a start/stop command with code 2: stop and eject. */
		if (scsi_simple(SCSI_STRTSTP, 2) != SENSE_NO_SENSE)
			return(EIO);
		return(OK);
	}
	/* Call the common code for disks and disk like devices. */
	return(do_diocntl(dp, m_ptr));

  default:
	return(ENOTTY);

  case SCSI_DEVTAPE:
	break;
  }
  /* Further ioctls are for tapes. */

  if (m_ptr->REQUEST == MTIOCTOP) {
	struct mtop op;
	phys_bytes op_phys;
	long delta;
	int key;
	byte *buf = tmp_buf;

	/* Basic tape commands: rewind, space, write eof marks, ... */
	op_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, sizeof(op));
	if (op_phys == 0) return(EINVAL);
	phys_copy(op_phys, vir2phys(&op), (phys_bytes) sizeof(op));

	switch(op.mt_op) {
	case MTREW:
	case MTOFFL:
	case MTRETEN:
	case MTFSF:
	case MTFSR:
	case MTBSF:
	case MTBSR:
	case MTEOM:
		/* Write an EOF mark before spacing. */
		if (sp->need_eof && sp->tstat.mt_dsreg != DS_ERR) {
			if (scsi_simple(SCSI_WREOF, 1) != SENSE_NO_SENSE)
				return(EIO);
			sp->tstat.mt_blkno = 0;
			sp->tstat.mt_fileno++;
			sp->need_eof = FALSE;
		}
		sp->at_eof = FALSE;
	}

	switch(op.mt_op) {
	case MTREW:
	case MTOFFL:
	case MTRETEN:
	case MTERASE:
		/* Rewind, Offline, Retension, Erase. */
		switch(op.mt_op) {
		case MTOFFL:
			if (scsi_simple(SCSI_LOADUNLD, 0) != SENSE_NO_SENSE)
				return(EIO);
			sp->state &= ~S_READY;
			break;
		case MTRETEN:
			if (scsi_simple(SCSI_LOADUNLD, 3) != SENSE_NO_SENSE)
				return(EIO);
			break;
		case MTERASE:
			if (scsi_simple(SCSI_REWIND, 0) != SENSE_NO_SENSE)
				return(EIO);
			if (scsi_simple(SCSI_ERASE, 1) != SENSE_NO_SENSE)
				return(EIO);
			/* Rewind once more. */
			/*FALL THROUGH*/
		case MTREW:
			if (scsi_simple(SCSI_REWIND, 0) != SENSE_NO_SENSE)
				return(EIO);
		}
		sp->tstat.mt_dsreg = DS_OK;
		sp->tstat.mt_blkno = 0;
		sp->tstat.mt_fileno = 0;
		break;
	case MTFSF:
	case MTFSR:
	case MTBSF:
	case MTBSR:
		if (sp->tstat.mt_dsreg == DS_ERR) return(EIO);
		group0();
		rq->ccb.opcode = CCB_INIT;
		ccb_cmd0(rq).scsi_op = SCSI_SPACE;
		delta = op.mt_count;
		if (op.mt_op == MTBSR) delta = -delta;
		if (op.mt_op == MTBSF) delta = -delta - 1;
		h2b24(ccb_cmd0(rq).trlength, delta);
		ccb_cmd0(rq).fixed =
				op.mt_op == MTFSR || op.mt_op == MTBSR ? 0 : 1;
		if ((key = scsi_command(0L, 0)) != SENSE_NO_SENSE) {
			if (sense_key(key) != SENSE_NO_SENSE) return(EIO);

			if (sense_eom(key)) {
				/* Banging into end of tape. */
				if (op.mt_op == MTBSF || op.mt_op == MTBSR) {
					/* Backspacing to start of tape. */
					sp->tstat.mt_dsreg = DS_EOF;
					sp->tstat.mt_blkno = 0;
					sp->tstat.mt_fileno = 0;
				} else {
					/* Not forwards please! */
					return(EIO);
				}
			}
			if (sense_eof(key)) {
				/* Reaching a filemark. */
				sp->tstat.mt_dsreg = DS_EOF;
				sp->at_eof = TRUE;
				if (op.mt_op == MTFSR) {
					/* Forwards. */
					sp->tstat.mt_blkno = 0;
					sp->tstat.mt_fileno++;
				} else {
					/* Backwards (bad idea!) */
					sp->tstat.mt_blkno = -1;
					sp->tstat.mt_fileno--;
				}
			}
		} else {
			if (op.mt_op == MTFSR || op.mt_op == MTBSR) {
				sp->tstat.mt_blkno += delta;
			} else {
				sp->tstat.mt_blkno = 0;
				sp->tstat.mt_fileno += delta;
			}
			if (op.mt_op == MTBSF) {
				/* n+1 backwards, and 1 forward. */
				group0();
				rq->ccb.opcode = CCB_INIT;
				ccb_cmd0(rq).scsi_op = SCSI_SPACE;
				h2b24(ccb_cmd0(rq).trlength, 1L);
				ccb_cmd0(rq).fixed = 1;
				if (scsi_command(0L, 0) != SENSE_NO_SENSE)
					return(EIO);
				sp->tstat.mt_fileno++;
			}
			sp->tstat.mt_dsreg = DS_OK;
		}
		break;
	case MTWEOF:
		/* Write EOF marks. */
		if (sp->tstat.mt_dsreg == DS_ERR) return(EIO);
		if (op.mt_count < 0) return(EIO);
		if (op.mt_count == 0) return(OK);
		group0();
		rq->ccb.opcode = CCB_INIT;
		ccb_cmd0(rq).scsi_op = SCSI_WREOF;
		h2b24(ccb_cmd0(rq).trlength, op.mt_count);
		if (scsi_command(0L, 0) != SENSE_NO_SENSE) return(EIO);
		sp->tstat.mt_dsreg = DS_OK;
		sp->tstat.mt_blkno = 0;
		sp->tstat.mt_fileno += op.mt_count;
		sp->need_eof = FALSE;
		break;
	case MTEOM:
		/* Forward space to end of media. */
		if (sp->tstat.mt_dsreg == DS_ERR) return(EIO);
		do {
			group0();
			rq->ccb.opcode = CCB_INIT;
			ccb_cmd0(rq).scsi_op = SCSI_SPACE;
			h2b24(ccb_cmd0(rq).trlength, 0x7FFFFF);
			ccb_cmd0(rq).fixed = 1;
			key = scsi_command(0L, 0);
			sp->tstat.mt_blkno = 0;
			sp->tstat.mt_fileno += 0x7FFFFF;
			if (key != SENSE_NO_SENSE) {
				if (key != SENSE_BLANK_CHECK) return(EIO);
				sp->tstat.mt_fileno -= sp->tstat.mt_resid;
			}
		} while (key == SENSE_NO_SENSE);
		sp->tstat.mt_dsreg = DS_OK;
		break;
	case MTBLKZ:
	case MTMODE:
		/* Select tape block size or tape density. */

		/* Rewind tape. */
		if (scsi_simple(SCSI_REWIND, 0) != SENSE_NO_SENSE)
			return(EIO);

		sp->tstat.mt_dsreg = DS_OK;
		sp->tstat.mt_blkno = 0;
		sp->tstat.mt_fileno = 0;

		if (op.mt_op == MTBLKZ && op.mt_count == 0) {
			/* Request for variable block size mode. */
			sp->tfixed = FALSE;
			sp->block_size = 1;
		} else {
			/* First a modesense to get the current values. */
			if (scsi_simple(SCSI_MDSENSE, 255) != SENSE_NO_SENSE)
				return(EIO);

			/* Must at least have one block descriptor. */
			if (buf[3] < 8) return(EIO);
			buf[0] = 0;
			buf[1] = 0;
			/* buf[2]: buffered mode & speed */
			buf[3] = 8;
			if (op.mt_op == MTMODE)		/* New density */
				buf[4 + 0] = op.mt_count;
			/* buf[4 + 1]: number of blocks */
			buf[4 + 4] = 0;
			if (op.mt_op == MTBLKZ)		/* New block size */
				h2b24(buf + 4 + 5, (long) op.mt_count);

			/* Set the new density/blocksize. */
			if (scsi_simple(SCSI_MDSELECT, 4+8) != SENSE_NO_SENSE)
				return(EIO);
			if (op.mt_op == MTBLKZ) {
				sp->tfixed = TRUE;
				sp->block_size= op.mt_count;
			}
		}
		sp->state &= ~S_READY;
		if (scsi_probe() != OK) return(EIO);
		break;
	default:
		/* Not implemented. */
		return(ENOTTY);
	}
  } else
  if (m_ptr->REQUEST == MTIOCGET) {
	/* Request tape status. */
	phys_bytes get_phys;

	get_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
							sizeof(sp->tstat));
	if (get_phys == 0) return(EINVAL);

	if (sp->tstat.mt_dsreg == DS_OK) {
		/* Old error data is never cleared (until now). */
		sp->tstat.mt_erreg = 0;
		sp->tstat.mt_resid = 0;
	}
	phys_copy(vir2phys(&sp->tstat), get_phys,
					(phys_bytes) sizeof(sp->tstat));
  } else {
	/* Not implemented. */
	return(ENOTTY);
  }
  return(OK);
}


/*===========================================================================*
 *				scsi_simple				     *
 *===========================================================================*/
PRIVATE int scsi_simple(opcode, count)
int opcode;				/* SCSI opcode */
int count;				/* count or flag */
{
/* The average group 0 SCSI command with just a simple flag or count. */

  vir_bytes len = 0;	/* Sometimes a buffer is used. */

  group0();
  rq->ccb.opcode = CCB_INIT;
  ccb_cmd0(rq).scsi_op = opcode;

  /* Fill in the count argument at the proper place. */
  switch (opcode) {
  case SCSI_REQSENSE:
  case SCSI_INQUIRY:
  case SCSI_MDSENSE:
  case SCSI_MDSELECT:
	ccb_cmd0(rq).nblocks = count;
	len = count;
	break;

  case SCSI_STRTSTP:
    /* SCSI_LOADUNLD: (synonym) */
	ccb_cmd0(rq).nblocks = count;
	break;

  case SCSI_RDLIMITS:
	len = count;
	break;

  case SCSI_WREOF:
	h2b24(ccb_cmd0(rq).trlength, (long) count);
	break;

  case SCSI_REWIND:
  case SCSI_ERASE:
	ccb_cmd0(rq).fixed = count;
	break;
  }
  return(scsi_command(tmp_phys, len));
}


/*===========================================================================*
 *				group0					     *
 *===========================================================================*/
PRIVATE void group0()
{
  /* Prepare the ccb for a group 0 SCSI command. */

  rq->ccb.cmdlen = sizeof(cdb0_t);

  /* Clear cdb to zeros the ugly way. */
  * (u32_t *) (rq->ccb.cmd + 0) = 0;
  * (u16_t *) (rq->ccb.cmd + 4) = 0;
}


/*===========================================================================*
 *				group1					     *
 *===========================================================================*/
PRIVATE void group1()
{
  rq->ccb.cmdlen = sizeof(cdb1_t);
  * (u32_t *) (rq->ccb.cmd + 0) = 0;
  * (u32_t *) (rq->ccb.cmd + 4) = 0;
  * (u16_t *) (rq->ccb.cmd + 8) = 0;
}


/*===========================================================================*
 *				scsi_command				     *
 *===========================================================================*/
PRIVATE int scsi_command(data, len)
phys_bytes data;
vir_bytes len;
{
/* Execute a SCSI command and return the results.  Unlike most other routines,
 * this routine returns the sense key of a SCSI command instead of OK or EIO.
 */
  struct scsi *sp = s_sp;
  int key;
  message intr_mess;

  rq->ccb.addrcntl = ccb_scid(s_sp->targ) | ccb_lun(s_sp->lun);

  if (rq->ccb.opcode == CCB_SCATTER) {
	/* Device read/write; add checks and use scatter/gather vector. */
	rq->ccb.addrcntl |= s_opcode == DEV_READ ? CCB_INCHECK : CCB_OUTCHECK;
	data = vir2phys(rq->dmalist);
	len = (byte *) rq->dmaptr - (byte *) rq->dmalist;
	if (aha_model == AHA1540) {
		/* A plain 1540 can't do s/g. */
		rq->ccb.opcode = CCB_INIT;
		data = b2h24(rq->dmalist[0].dataptr);
		len = b2h24(rq->dmalist[0].datalen);
	}
  }
  h2b24(rq->ccb.datalen, (u32_t) len);
  h2b24(rq->ccb.dataptr, data);
  dump_scsi_cmd();

  mailbox[0].status = AHA_MBOXSTART;

  out_byte(AHA_DATAREG, AHACOM_STARTSCSI);  /* hey, you've got mail! */

  /* Wait for the SCSI command to complete. */
  while (mailbox[1].status == AHA_MBOXFREE) {
	/* No mail yet, wait for an interrupt. */
	receive(HARDWARE, &intr_mess);
  }
  mailbox[1].status = AHA_MBOXFREE;	/* free up inbox */

  /* Check the results of the operation. */
  if (rq->ccb.hastat != 0) {
	/* Weird host adapter status. */
	printf("%s: host adapter error 0x%02x%s\n", s_name(), rq->ccb.hastat,
		rq->ccb.hastat == HST_TIMEOUT ? " (Selection timeout)" : "");
	errordump();
	if (sp->devtype == SCSI_DEVTAPE) sp->tstat.mt_dsreg = DS_ERR;
	memset((void *) &ccb_sense(rq), 0, sizeof(sense_t));
	return(SENSE_HARDWARE);
  }

  if (rq->ccb.tarstat != 0) {
	/* A SCSI error has occurred. */
	sense_t *sense = &ccb_sense(rq);

	if (sense->len < 2) {
		/* No additional code and qualifier, zero them. */
		sense->add_code = sense->add_qual = 0;

⌨️ 快捷键说明

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