1
0
mirror of https://github.com/simh/simh.git synced 2026-01-11 23:52:58 +00:00

SCSI: Add some QIC tape reading support

These changes were merged from the 3b2-700 commit into the SCSI code here

Comments thoughts from Mark Pizzolato:
- This logic will work only with some archived QIC tape images that
  happen to contain only 512 byte records.  According to the master
  archiver (Al Kossow) QIC tapes have been archived with varying
  record sizes which are multiples of 512 bytes.  The logic in sim_scsi
  should handle reading 512 byte chunks from logical tape records
  which are multiples of that size.  This logic does not do that.
This commit is contained in:
Seth Morabito 2022-11-06 16:41:24 -10:00 committed by Mark Pizzolato
parent c3e306d2c3
commit c73a497fd2
2 changed files with 83 additions and 30 deletions

View File

@ -209,10 +209,13 @@ struct DRVTYP {
#define DRVFL_NOCHNG (1u << DRVFL_V_NOCHNG) /* Can't change drive type once set */
#define DRVFL_V_NORMV (DRVFL_V_NOCHNG + 1)
#define DRVFL_NORMV (1u << DRVFL_V_NORMV) /* Can't change to a removable drive */
#define DRVFL_V_QICTAPE (DRVFL_V_NORMV + 1)
#define DRVFL_QICTAPE (1u << DRVFL_V_QICTAPE) /* drive is a QIC (Quarter Inch Cartridge) tape */
/* DRVTYP Initializer for SCSI disk and/or tape */
#define DRV_SCSI(typ, pq, ver, rmv, bsz, lbn, man, prd, rev, nm, gap, txt) \
46, 9, 1549, lbn, nm, bsz, (rmv == TRUE) ? DRVFL_RMV : 0, \
46, 9, 1549, lbn, nm, bsz, \
DRVFL_TYPE_SCSI | ((rmv == TRUE) ? DRVFL_RMV|DRVFL_QICTAPE : 0), \
NULL, 0, 0, NULL, txt, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
typ, pq, ver, man, prd, rev, gap

View File

@ -489,6 +489,9 @@ scsi_set_req (bus); /* request to send data
void scsi_mode_sel6 (SCSI_BUS *bus, uint8 *data, uint32 len)
{
UNIT *uptr = bus->dev[bus->target];
uint32 blk_size;
if (bus->phase == SCSI_CMD) {
scsi_debug_cmd (bus, "Mode Select(6) - CMD\n");
memcpy (&bus->cmd[0], &data[0], 6);
@ -498,9 +501,25 @@ if (bus->phase == SCSI_CMD) {
}
else if (bus->phase == SCSI_DATO) {
scsi_debug_cmd (bus, "Mode Select(6) - DATO\n");
/* Not currently implemented so just return
good status for now */
scsi_status (bus, STS_OK, KEY_OK, ASC_OK);
if ((DRVFL_GET_IFTYPE(uptr->drvtyp) == SCSI_TAPE) &&
(uptr->drvtyp->flags & DRVFL_QICTAPE)) {
blk_size = ((uint32)bus->buf[9]) << 16 |
((uint32)bus->buf[10]) << 8 |
(uint32)bus->buf[11];
/* QIC tape ONLY supports requesting a fixed block size of
* 0x200 bytes. Any other block size will cause an illegal
* request. */
if (blk_size == uptr->drvtyp->sectsize) {
scsi_status(bus, STS_OK, KEY_OK, ASC_OK);
}
else {
scsi_status(bus, STS_CHK, KEY_ILLREQ|KEY_M_ILI, ASC_INVCDB);
}
}
else {
/* Not implemented for disk and non-QIC tape */
scsi_status(bus, STS_OK, KEY_OK, ASC_OK);
}
}
}
@ -778,8 +797,9 @@ scsi_set_req (bus); /* request to send data
void scsi_read6_tape (SCSI_BUS *bus, uint8 *data, uint32 len)
{
UNIT *uptr = bus->dev[bus->target];
t_seccnt sects, sectsread;
t_seccnt sects, sectsread, new_buf_b;
t_stat r;
uint32 i;
if ((data[1] & 0x3) == 0x3) { /* SILI and FIXED? */
scsi_status (bus, STS_CHK, KEY_ILLREQ, ASC_INVCDB);
@ -787,6 +807,7 @@ if ((data[1] & 0x3) == 0x3) { /* SILI and FIXED? */
}
sects = GETW (data, 3) | (data[2] << 16);
new_buf_b = 0;
sectsread = 0;
if (sects == 0) { /* no data to read */
@ -797,35 +818,64 @@ if (sects == 0) { /* no data to read */
scsi_debug_cmd (bus, "Read(6) blks %d fixed %d\n", sects, (data[1] & 0x1));
if (uptr->flags & UNIT_ATT) {
if (data[1] & 0x1) {
r = sim_tape_rdrecf (uptr, &bus->buf[0], &sectsread, (sects * uptr->drvtyp->sectsize));
scsi_debug_cmd (bus, "Read tape blk %d, read %d, r = %d\n", sects, sectsread, r);
if (uptr->drvtyp->flags & DRVFL_QICTAPE) {
if (data[1] & 0x1) {
/* If this is a QIC tape drive and bit 0 is set, this is a
request to read multiple fixed-length blocks. */
scsi_debug_cmd(bus, "QIC in fixed block mode\n");
for (i = 0; i < sects; i++) {
r = sim_tape_rdrecf(uptr, &bus->buf[new_buf_b], &sectsread, uptr->drvtyp->sectsize);
scsi_debug_cmd(bus, "Read tape blk %d, read %d, r = %d\n",
sects, sectsread, r);
if (r == MTSE_OK) {
new_buf_b += uptr->drvtyp->sectsize;
} else {
scsi_tape_status(bus, r);
scsi_status(bus, bus->status, bus->sense_key, bus->sense_code);
return;
}
}
} else {
/* QIC drives respond with an illegal request when the
request does not specify fixed-block mode */
scsi_debug_cmd(bus, "QIC not in fixed block mode, invalid command\n");
scsi_status(bus, STS_CHK, KEY_ILLREQ|KEY_M_ILI, ASC_INVCDB);
return;
}
}
else {
r = sim_tape_rdrecf (uptr, &bus->buf[0], &sectsread, sects);
scsi_debug_cmd (bus, "Read tape max %d, read %d, r = %d\n", sects, sectsread, r);
if (r == MTSE_INVRL) { /* overlength condition */
scsi_debug_cmd (bus, "Overlength\n");
if ((data[1] & 0x2) && (uptr->drvtyp->sectsize == 0)) { /* SILI set */
scsi_debug_cmd (bus, "SILI set\n");
/* Otherwise, this is a normal streaming tape read */
if (data[1] & 0x1) {
r = sim_tape_rdrecf (uptr, &bus->buf[0], &sectsread, (sects * uptr->drvtyp->sectsize));
scsi_debug_cmd (bus, "Read tape blk %d, read %d, r = %d\n", sects, sectsread, r);
}
else {
r = sim_tape_rdrecf (uptr, &bus->buf[0], &sectsread, sects);
scsi_debug_cmd (bus, "Read tape max %d, read %d, r = %d\n", sects, sectsread, r);
if (r == MTSE_INVRL) { /* overlength condition */
scsi_debug_cmd (bus, "Overlength\n");
if ((data[1] & 0x2) && (uptr->drvtyp->sectsize == 0)) { /* SILI set */
scsi_debug_cmd (bus, "SILI set\n");
}
else {
scsi_debug_cmd (bus, "SILI not set - check condition\n");
scsi_status (bus, STS_CHK, (KEY_OK | KEY_M_ILI), ASC_OK);
return;
}
}
else {
scsi_debug_cmd (bus, "SILI not set - check condition\n");
scsi_status (bus, STS_CHK, (KEY_OK | KEY_M_ILI), ASC_OK);
return;
}
}
else if ((r == MTSE_OK) && (sectsread < sects)) { /* underlength condition */
scsi_debug_cmd (bus, "Underlength\n");
if (data[1] & 0x2) { /* SILI set */
scsi_debug_cmd (bus, "SILI set\n");
}
else {
scsi_debug_cmd (bus, "SILI not set - check condition\n");
scsi_status_deferred (bus, STS_CHK, (KEY_OK | KEY_M_ILI), ASC_OK);
bus->sense_info = (sects - sectsread);
else if ((r == MTSE_OK) && (sectsread < sects)) { /* underlength condition */
scsi_debug_cmd (bus, "Underlength\n");
if (data[1] & 0x2) { /* SILI set */
scsi_debug_cmd (bus, "SILI set\n");
}
else {
scsi_debug_cmd (bus, "SILI not set - check condition\n");
scsi_status_deferred (bus, STS_CHK, (KEY_OK | KEY_M_ILI), ASC_OK);
bus->sense_info = (sects - sectsread);
}
}
}
new_buf_b = sectsread;
}
if (r != MTSE_OK) {
@ -839,7 +889,7 @@ else {
}
if (sectsread > 0) {
bus->buf_b = sectsread;
bus->buf_b = new_buf_b;
scsi_set_phase (bus, SCSI_DATI); /* data in phase next */
}
else {