From 48f1430bd0ec8fe70ffc4c4db9c22c4f82af2aa4 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 7 Nov 2022 10:46:40 -1000 Subject: [PATCH] 3B2: Migrate 3b2_scsi to use updated sim_scsi, sim_disk and sim_tape Started from pending 3b2-700 3b2_scsi.c and 3b2_scsi.h --- 3B2/3b2_scsi.c | 1077 +++++++++++++++++++++++------------------------- 3B2/3b2_scsi.h | 185 +++++---- 2 files changed, 634 insertions(+), 628 deletions(-) diff --git a/3B2/3b2_scsi.c b/3B2/3b2_scsi.c index 4e79051c..d14e156b 100644 --- a/3B2/3b2_scsi.c +++ b/3B2/3b2_scsi.c @@ -1,6 +1,6 @@ -/* 3b2_scsi.c: AT&T 3B2 SCSI (CM195W) feature card +/* 3b2_scsi.c: CM195W SCSI Controller CIO Card - Copyright (c) 2020, Seth J. Morabito + Copyright (c) 2020-2022, Seth J. Morabito Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -37,25 +37,17 @@ #include "3b2_io.h" #include "3b2_mem.h" -#define PUMP_CRC 0x201b3617 +#define DIAG_CRC_1 0x271b114c +#define PUMP_CRC 0x201b3617 + +#define HA_SCSI_ID 0 +#define HA_MAXFR (1u << 16) static void ha_cmd(uint8 op, uint8 subdev, uint32 addr, int32 len, t_bool express); -static void ha_build_req(uint8 subdev, t_bool express); -static void ha_ctrl(); -static void ha_write(); -static void ha_write_ext(); -static void ha_read_ext(); -static void ha_read_capacity(); +static void ha_build_req(uint8 tc, uint8 subdev, t_bool express); +static void ha_ctrl(uint8 tc); -static void dump_rep(); -static void dump_req(); -static void dump_edt(); - -/* Do not initiate host IRQ if ivec is <= this value */ -#define SCSI_MIN_IVEC 1 -#define HA_SCSI_ID 0 -#define HA_MAXFR (1u << 16) HA_STATE ha_state; SCSI_BUS ha_bus; @@ -64,17 +56,20 @@ int8 ha_subdev_tab[8]; /* Map of subdevice to SCSI target */ uint8 ha_subdev_cnt; uint32 ha_crc = 0; uint32 cq_offset = 0; +t_bool ha_conf = FALSE; static DRVTYP ha_tab[] = { + HA_DISK(SD155), + HA_DISK(SD300), HA_DISK(SD327), + HA_DISK(SD630), HA_TAPE(ST120) }; -#define SCSI_U_FLAGS (UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE) - UNIT ha_unit[9] = {0}; /* SCSI ID 0-7 + CIO Unit */ +#define SCSI_U_FLAGS (UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS+UNIT_ROABLE) -static UNIT *cio_unit = &ha_unit[8]; +static UNIT *cio_unit = &ha_unit[0]; MTAB ha_mod[] = { { SCSI_WLK, 0, NULL, "WRITEENABLED", @@ -96,6 +91,7 @@ static DEBTAB ha_debug[] = { { "SBUS", SCSI_DBG_BUS, "SCSI bus activity" }, { "SMSG", SCSI_DBG_MSG, "SCSI messages" }, { "SDSK", SCSI_DBG_DSK, "SCSI disk activity" }, + { "STAP", MTSE_DBG_API, "SCSI tape activity" }, { NULL } }; @@ -104,7 +100,7 @@ DEVICE ha_dev = { ha_unit, /* units */ NULL, /* registers */ ha_mod, /* modifiers */ - 9, /* #units */ + 8, /* #units */ 16, /* address radix */ 32, /* address width */ 1, /* address incr. */ @@ -130,34 +126,29 @@ DEVICE ha_dev = { &ha_tab }; -void ha_cio_reset(uint8 cid) +void ha_cio_reset(uint8 slot) { sim_debug(HA_TRACE, &ha_dev, - "[%08x] Handling CIO reset\n", - R[NUM_PC]); + "Handling CIO reset\n"); ha_state.pump_state = PUMP_NONE; ha_crc = 0; } t_stat ha_reset(DEVICE *dptr) { - uint8 cid; + uint8 slot; uint32 t; UNIT *uptr; t_stat r; static t_bool inited = FALSE; - sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_reset] Resetting SCSI device\n", - R[NUM_PC]); - if (!inited) { inited = TRUE; for (t = 0; t < dptr->numunits - 1; t++) { uptr = dptr->units + t; uptr->action = &ha_svc; uptr->flags = SCSI_U_FLAGS; - sim_disk_set_drive_type_by_name (uptr, "SD327"); + sim_disk_set_drive_type_by_name (uptr, "SD155"); } uptr = dptr->units + t; uptr->action = &ha_svc; @@ -190,57 +181,20 @@ t_stat ha_reset(DEVICE *dptr) } if (dptr->flags & DEV_DIS) { - sim_debug(HA_TRACE, &ha_dev, - "[ha_reset] REMOVING CARD\n"); + cio_remove_all(HA_ID); + ha_conf = FALSE; + return SCPE_OK; + } - for (cid = 0; cid < CIO_SLOTS; cid++) { - if (cio[cid].id == HA_ID) { - break; - } + if (!ha_conf) { + r = cio_install(HA_ID, "SCSI", HA_IPL, + &ha_express, &ha_full, &ha_sysgen, &ha_cio_reset, + &slot); + if (r != SCPE_OK) { + return r; } - - if (cid == CIO_SLOTS) { - /* No card was ever attached */ - return SCPE_OK; - } - - cio[cid].id = 0; - cio[cid].ipl = 0; - cio[cid].ivec = 0; - cio[cid].exp_handler = NULL; - cio[cid].full_handler = NULL; - cio[cid].sysgen = NULL; - - ha_state.initialized = FALSE; - - } else if (!ha_state.initialized) { - sim_debug(HA_TRACE, &ha_dev, - "[ha_reset] Attaching SCSI Card\n"); - - /* Find the first available slot */ - for (cid = 0; cid < CIO_SLOTS; cid++) { - if (cio[cid].id == 0) { - break; - } - } - - if (cid == CIO_SLOTS) { - return SCPE_NXM; - } - - cio[cid].id = HA_ID; - cio[cid].ipl = HA_IPL; - cio[cid].exp_handler = &ha_express; - cio[cid].full_handler = &ha_full; - cio[cid].reset_handler = &ha_cio_reset; - cio[cid].sysgen = &ha_sysgen; - - ha_state.initialized = TRUE; - ha_state.cid = cid; - - sim_debug(HA_TRACE, &ha_dev, - "[ha_reset] SCSI Card now enabled in IO Slot %d\n", - cid); + ha_state.slot = slot; + ha_conf = TRUE; } return SCPE_OK; @@ -248,17 +202,17 @@ t_stat ha_reset(DEVICE *dptr) static void ha_calc_subdevs() { - uint32 target; + uint32 tc; UNIT *uptr; ha_subdev_cnt = 0; memset(ha_subdev_tab, -1, 8); - for (target = 0; target < 8; target++) { - uptr = &ha_unit[target]; + for (tc = 0; tc < 8; tc++) { + uptr = &ha_unit[tc]; if (uptr->flags & UNIT_ATT) { - ha_subdev_tab[ha_subdev_cnt++] = target; + ha_subdev_tab[ha_subdev_cnt++] = tc; } } } @@ -283,60 +237,88 @@ t_stat ha_svc(UNIT *uptr) { cio_entry cqe; uint8 capp_data[CAPP_LEN] = {0}; + int8 i, tc = -1; + uint8 svc_req = 0; + ha_req *req = NULL; + ha_resp *rep = NULL; - /* Finish any pending job */ - if (ha_state.reply.pending) { - ha_state.reply.pending = FALSE; + sim_debug(HA_TRACE, &ha_dev, + "[ha_svc] SERVICE ROUTINE\n"); - switch(ha_state.reply.type) { - case HA_JOB_QUICK: - ha_fcm_express(); - - sim_debug(HA_TRACE, &ha_dev, - "[ha_svc] FAST MODE CQ: status=%02x op=%02x subdev=%02x ssb=%02x\n", - ha_state.reply.status, ha_state.reply.op, ha_state.reply.subdev, ha_state.reply.ssb); - break; - case HA_JOB_EXPRESS: - case HA_JOB_FULL: - cqe.byte_count = ha_state.reply.len; - cqe.opcode = ha_state.reply.status; /* Yes, status, not opcode! */ - cqe.subdevice = ha_state.reply.subdev; - cqe.address = ha_state.reply.addr; - - sim_debug(HA_TRACE, &ha_dev, - "[ha_svc] CQE: byte_count=%04x, opcode=%02x, subdevice=%02x, addr=%08x\n", - cqe.byte_count, cqe.opcode, cqe.subdevice, cqe.address); - - if (ha_state.reply.type == HA_JOB_EXPRESS) { + /* Determine how many targets need servicing */ + for (i = 0; i < 8; i++) { + if (ha_state.ts[i].pending) { + if (req == NULL && rep == NULL) { + tc = i; sim_debug(HA_TRACE, &ha_dev, - "[ha_svc] EXPRESS MODE CQ: byte_count=%02x op=%02x subdev=%02x address=%08x\n", - cqe.byte_count, cqe.opcode, cqe.subdevice, cqe.address); - - cio_cexpress(ha_state.cid, SCQCESIZE, &cqe, capp_data); - } else { - sim_debug(HA_TRACE, &ha_dev, - "[ha_svc] FULL MODE CQ: status=%02x op=%02x subdev=%02x ssb=%02x\n", - ha_state.reply.status, ha_state.reply.op, ha_state.reply.subdev, ha_state.reply.ssb); - - cio_cqueue(ha_state.cid, 0, SCQCESIZE, &cqe, capp_data); + "[ha_svc] Found a job for target %d\n", + tc); + req = &ha_state.ts[i].req; + rep = &ha_state.ts[i].rep; + ha_state.ts[i].pending = FALSE; } - break; + svc_req++; } - - dump_rep(); } - if (cio[ha_state.cid].ivec > SCSI_MIN_IVEC) { + if (tc == -1) { + return SCPE_OK; + } + + switch(rep->type) { + case HA_JOB_QUICK: + ha_fcm_express(tc); + sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_svc] IRQ for board %d (VEC=%d).\n", - R[NUM_PC], ha_state.cid, cio[ha_state.cid].ivec); - CIO_SET_INT(ha_state.cid); + "[ha_svc] FAST MODE CQ: target=%d status=%02x op=%02x subdev=%02x ssb=%02x\n", + tc, rep->status, rep->op, rep->subdev, rep->ssb); + break; + case HA_JOB_EXPRESS: + case HA_JOB_FULL: + cqe.byte_count = rep->len; + cqe.opcode = rep->status; /* Yes, status, not opcode! */ + cqe.subdevice = rep->subdev; + cqe.address = rep->addr; + + sim_debug(HA_TRACE, &ha_dev, + "[ha_svc] CQE: target=%d, byte_count=%04x, opcode=%02x, subdevice=%02x, addr=%08x\n", + tc, cqe.byte_count, cqe.opcode, cqe.subdevice, cqe.address); + + if (rep->type == HA_JOB_EXPRESS) { + sim_debug(HA_TRACE, &ha_dev, + "[ha_svc] EXPRESS MODE CQ: target=%d, byte_count=%02x " + "op=%02x subdev=%02x address=%08x\n", + tc, cqe.byte_count, cqe.opcode, cqe.subdevice, cqe.address); + + cio_cexpress(ha_state.slot, SCQCESIZE, &cqe, capp_data); + } else { + sim_debug(HA_TRACE, &ha_dev, + "[ha_svc] FULL MODE CQ: target=%d, status=%02x op=%02x subdev=%02x ssb=%02x\n", + tc, rep->status, rep->op, rep->subdev, rep->ssb); + + cio_cqueue(ha_state.slot, 0, SCQCESIZE, &cqe, capp_data); + } + break; + } + + sim_debug(HA_TRACE, &ha_dev, + "[ha_svc] IRQ for board %d (VEC=%d). PSW_CUR_IPL=%d\n", + ha_state.slot, cio[ha_state.slot].ivec, PSW_CUR_IPL); + + CIO_SET_INT(ha_state.slot); + + /* There's more work to do after this job is done */ + if (svc_req > 1) { + sim_debug(HA_TRACE, &ha_dev, + "[ha_svc] Scheduling job to handle another %d open requests\n", + svc_req - 1); + sim_activate_abs(uptr, 1000); } return SCPE_OK; } -void ha_sysgen(uint8 cid) +void ha_sysgen(uint8 slot) { uint32 sysgen_p; uint32 alert_buf_p; @@ -344,92 +326,89 @@ void ha_sysgen(uint8 cid) cq_offset = 0; sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] Handling Sysgen.\n"); - sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] rqp=%08x\n", cio[cid].rqp); - sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] cqp=%08x\n", cio[cid].cqp); - sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] rqs=%d\n", cio[cid].rqs); - sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] cqs=%d\n", cio[cid].cqs); - sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] ivec=%d\n", cio[cid].ivec); - sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] no_rque=%d\n", cio[cid].no_rque); + sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] rqp=%08x\n", cio[slot].rqp); + sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] cqp=%08x\n", cio[slot].cqp); + sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] rqs=%d\n", cio[slot].rqs); + sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] cqs=%d\n", cio[slot].cqs); + sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] ivec=%d\n", cio[slot].ivec); + sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] no_rque=%d\n", cio[slot].no_rque); - sysgen_p = pread_w(SYSGEN_PTR); - alert_buf_p = pread_w(sysgen_p + 12); + sysgen_p = pread_w(SYSGEN_PTR, BUS_PER); + alert_buf_p = pread_w(sysgen_p + 12, BUS_PER); sim_debug(HA_TRACE, &ha_dev, "[ha_sysgen] alert_bfr=%08x\n", alert_buf_p); - ha_state.frq = (cio[cid].no_rque == 0); + ha_state.frq = (cio[slot].no_rque == 0); - ha_state.reply.type = ha_state.frq ? HA_JOB_QUICK : HA_JOB_EXPRESS; - ha_state.reply.addr = 0; - ha_state.reply.len = 0; - ha_state.reply.status = 3; - ha_state.reply.op = 0; - ha_state.reply.pending = TRUE; + ha_state.ts[HA_SCSI_ID].rep.type = ha_state.frq ? HA_JOB_QUICK : HA_JOB_EXPRESS; + ha_state.ts[HA_SCSI_ID].rep.addr = 0; + ha_state.ts[HA_SCSI_ID].rep.len = 0; + ha_state.ts[HA_SCSI_ID].rep.status = 3; + ha_state.ts[HA_SCSI_ID].rep.op = 0; + ha_state.ts[HA_SCSI_ID].pending = TRUE; if (ha_crc == PUMP_CRC) { sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_full] PUMP: NEW STATE = PUMP_SYSGEN\n", - R[NUM_PC]); + "[ha_sysgen] PUMP: NEW STATE = PUMP_SYSGEN\n"); ha_state.pump_state = PUMP_SYSGEN; } else { sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_full] PUMP: NEW STATE = PUMP_NONE\n", - R[NUM_PC]); + "[ha_sysgen] PUMP: NEW STATE = PUMP_NONE\n"); ha_state.pump_state = PUMP_NONE; } - sim_activate_abs(cio_unit, 100000); + sim_activate_abs(cio_unit, 1000); } void ha_fast_queue_check() { uint8 busy, op, subdev; - uint32 timeout, addr, len, rqp; - rqp = cio[ha_state.cid].rqp; + uint32 addr, len, rqp; - busy = pread_b(rqp); - op = pread_b(rqp + 1); - subdev = pread_b(rqp + 2); - timeout = pread_w(rqp + 4); - addr = pread_w(rqp + 8); - len = pread_w(rqp + 12); + rqp = cio[ha_state.slot].rqp; + + busy = pread_b(rqp, BUS_PER); + op = pread_b(rqp + 1, BUS_PER); + subdev = pread_b(rqp + 2, BUS_PER); + /* 4-byte timeout value at rqp + 4 not used */ + addr = pread_w(rqp + 8, BUS_PER); + len = pread_w(rqp + 12, BUS_PER); if (busy == 0xff || ha_state.pump_state != PUMP_COMPLETE) { sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_fast_queue_check] Job pending (opcode=0x%02x subdev=%02x)\n", - R[NUM_PC], op, subdev); - pwrite_b(rqp, 0); /* Job has been taken */ + "[ha_fast_queue_check] Job pending (opcode=0x%02x subdev=%02x)\n", + op, subdev); + pwrite_b(rqp, 0, BUS_PER); /* Job has been taken */ ha_cmd(op, subdev, addr, len, FALSE); } } -void ha_express(uint8 cid) +void ha_express(uint8 slot) { cio_entry rqe; uint8 rapp_data[RAPP_LEN] = {0}; - sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_express] Handling Express Request\n", - R[NUM_PC]); - if (ha_state.frq) { ha_fast_queue_check(); } else { - cio_rexpress(cid, SCQRESIZE, &rqe, rapp_data); + cio_rexpress(slot, SCQRESIZE, &rqe, rapp_data); - ha_cmd(rqe.opcode, rqe.subdevice, rqe.address, - rqe.byte_count, TRUE); + sim_debug(HA_TRACE, &ha_dev, + "[ha_express] Handling Express Request. subdev=%02x\n", + rqe.subdevice); + + ha_cmd(rqe.opcode, rqe.subdevice, rqe.address, rqe.byte_count, TRUE); } } -void ha_full(uint8 cid) +void ha_full(uint8 slot) { sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_full] Handling Full Request (INT3)\n", - R[NUM_PC]); + "[ha_full] Handling Full Request (INT3)\n"); if (ha_state.pump_state == PUMP_SYSGEN) { sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_full] PUMP: NEW STATE = PUMP_COMPLETE\n", - R[NUM_PC]); + "[ha_full] PUMP: NEW STATE = PUMP_COMPLETE\n"); + ha_state.pump_state = PUMP_COMPLETE; } @@ -437,57 +416,11 @@ void ha_full(uint8 cid) ha_fast_queue_check(); } else { sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_full] NON_FRQ NOT HANDLED\n", - R[NUM_PC]); + "[ha_full] NON_FRQ NOT HANDLED\n"); } } -static void dump_req() -{ - sim_debug(HA_TRACE, &ha_dev, - "[REQ] [%08x] %08x\n", - cio[ha_state.cid].rqp, - pread_w(cio[ha_state.cid].rqp)); - sim_debug(HA_TRACE, &ha_dev, - "[REQ] [%08x] %08x\n", - cio[ha_state.cid].rqp + 4, - pread_w(cio[ha_state.cid].rqp + 4)); - sim_debug(HA_TRACE, &ha_dev, - "[REQ] [%08x] %08x\n", - cio[ha_state.cid].rqp + 8, - pread_w(cio[ha_state.cid].rqp + 8)); - sim_debug(HA_TRACE, &ha_dev, - "[REQ] [%08x] %08x\n", - cio[ha_state.cid].rqp + 12, - pread_w(cio[ha_state.cid].rqp + 12)); - sim_debug(HA_TRACE, &ha_dev, - "[REQ] [%08x] %08x\n", - cio[ha_state.cid].rqp + 16, - pread_w(cio[ha_state.cid].rqp + 16)); - sim_debug(HA_TRACE, &ha_dev, - "[REQ] [%08x] %08x\n", - cio[ha_state.cid].rqp + 20, - pread_w(cio[ha_state.cid].rqp + 20)); - sim_debug(HA_TRACE, &ha_dev, - "[REQ] [%08x] %08x\n", - cio[ha_state.cid].rqp + 24, - pread_w(cio[ha_state.cid].rqp + 24)); -} - -static void dump_rep() -{ - uint32 i; - uint32 cqs = cio[ha_state.cid].cqs; - - for (i = 0; i < cqs; i++) { - sim_debug(HA_TRACE, &ha_dev, - "[CEQ] [%08x] %08x\n", - cio[ha_state.cid].cqp + (i * 4), - pread_w(cio[ha_state.cid].cqp + (i * 4))); - } -} - -static void ha_boot_disk(UNIT *uptr, uint8 target) +static void ha_boot_disk(UNIT *uptr, uint8 tc) { t_seccnt sectsread; t_stat r; @@ -500,7 +433,7 @@ static void ha_boot_disk(UNIT *uptr, uint8 target) if (r != SCPE_OK) { sim_debug(HA_TRACE, &ha_dev, "[ha_boot_disk] Could not read LBA 0\n"); - HA_STAT(HA_CKCON, CIO_SUCCESS); + HA_STAT(tc, HA_CKCON, CIO_SUCCESS); return; } @@ -510,7 +443,7 @@ static void ha_boot_disk(UNIT *uptr, uint8 target) "[ha_boot_disk] Storing PD block at 0x%08x.\n", HA_PDINFO_ADDR); for (i = 0; i < HA_BLKSZ; i++) { - pwrite_b(HA_PDINFO_ADDR + i, buf[i]); + pwrite_b(HA_PDINFO_ADDR + i, buf[i], BUS_PER); } @@ -528,20 +461,20 @@ static void ha_boot_disk(UNIT *uptr, uint8 target) boot_loc, HA_BOOT_ADDR); for (i = 0; i < HA_BLKSZ; i++) { - pwrite_b(HA_BOOT_ADDR + i, buf[i]); + pwrite_b(HA_BOOT_ADDR + i, buf[i], BUS_PER); } sim_debug(HA_TRACE, &ha_dev, "[ha_boot_disk] Done storing boot block at 0x%08x\n", HA_BOOT_ADDR); - HA_STAT(HA_GOOD, CIO_SUCCESS); + HA_STAT(tc, HA_GOOD, CIO_SUCCESS); - ha_state.reply.addr = HA_BOOT_ADDR; - ha_state.reply.len = HA_BLKSZ; + ha_state.ts[tc].rep.addr = HA_BOOT_ADDR; + ha_state.ts[tc].rep.len = HA_BLKSZ; } -static void ha_boot_tape(UNIT *uptr) +static void ha_boot_tape(UNIT *uptr, uint8 tc) { t_seccnt sectsread; t_stat r; @@ -551,7 +484,7 @@ static void ha_boot_tape(UNIT *uptr) if (!(uptr->flags & UNIT_ATT)) { sim_debug(HA_TRACE, &ha_dev, "[ha_boot_tape] Target not attached\n"); - HA_STAT(HA_CKCON, CIO_SUCCESS); + HA_STAT(tc, HA_CKCON, CIO_SUCCESS); return; } @@ -560,7 +493,7 @@ static void ha_boot_tape(UNIT *uptr) if (r != SCPE_OK) { sim_debug(HA_TRACE, &ha_dev, "[ha_boot_tape] Could not rewind tape\n"); - HA_STAT(HA_CKCON, CIO_SUCCESS); + HA_STAT(tc, HA_CKCON, CIO_SUCCESS); return; } @@ -569,12 +502,12 @@ static void ha_boot_tape(UNIT *uptr) if (r != SCPE_OK) { sim_debug(HA_TRACE, &ha_dev, "[ha_boot_tape] Could not read PD block.\n"); - HA_STAT(HA_CKCON, CIO_SUCCESS); + HA_STAT(tc, HA_CKCON, CIO_SUCCESS); return; } for (i = 0; i < HA_BLKSZ; i++) { - pwrite_b(HA_BOOT_ADDR + i, buf[i]); + pwrite_b(HA_BOOT_ADDR + i, buf[i], BUS_PER); } sim_debug(HA_TRACE, &ha_dev, @@ -583,13 +516,13 @@ static void ha_boot_tape(UNIT *uptr) r = sim_tape_sprecf(uptr, §sread); /* Skip block 1 */ - HA_STAT(HA_GOOD, CIO_SUCCESS); + HA_STAT(tc, HA_GOOD, CIO_SUCCESS); - ha_state.reply.addr = HA_BOOT_ADDR; - ha_state.reply.len = HA_BLKSZ; + ha_state.ts[tc].rep.addr = HA_BOOT_ADDR; + ha_state.ts[tc].rep.len = HA_BLKSZ; } -static void ha_read_block_tape(UNIT *uptr, uint32 addr) +static void ha_read_block_tape(UNIT *uptr, uint32 addr, uint8 tc) { t_seccnt sectsread; t_stat r; @@ -599,7 +532,7 @@ static void ha_read_block_tape(UNIT *uptr, uint32 addr) if (!(uptr->flags & UNIT_ATT)) { sim_debug(HA_TRACE, &ha_dev, "[ha_read_block_tape] Target not attached\n"); - HA_STAT(HA_CKCON, CIO_SUCCESS); + HA_STAT(tc, HA_CKCON, CIO_SUCCESS); return; } @@ -608,62 +541,85 @@ static void ha_read_block_tape(UNIT *uptr, uint32 addr) if (r != SCPE_OK) { sim_debug(HA_TRACE, &ha_dev, "[ha_read_block_tape] Could not read next block.\n"); - HA_STAT(HA_CKCON, CIO_SUCCESS); + HA_STAT(tc, HA_CKCON, CIO_SUCCESS); return; } for (i = 0; i < HA_BLKSZ; i++) { - pwrite_b(addr + i, buf[i]); + pwrite_b(addr + i, buf[i], BUS_PER); } sim_debug(HA_TRACE, &ha_dev, "[ha_read_block_tape] Transfered 512 bytes to 0x%08x\n", addr); - HA_STAT(HA_GOOD, CIO_SUCCESS); + HA_STAT(tc, HA_GOOD, CIO_SUCCESS); - ha_state.reply.addr = addr; - ha_state.reply.len = HA_BLKSZ; + ha_state.ts[tc].rep.addr = addr; + ha_state.ts[tc].rep.len = HA_BLKSZ; } -static void ha_read_block_disk(UNIT *uptr, uint8 target, uint32 addr, uint32 lba) +static void ha_read_block_disk(UNIT *uptr, uint32 addr, uint8 tc, uint32 lba) { t_seccnt sectsread; t_stat r; uint8 buf[HA_BLKSZ]; uint32 i; - sim_debug(HA_TRACE, &ha_dev, - "[ha_read_block_disk] Block translated from LBA 0x%X to PBA 0x%X\n", - lba, lba); - r = sim_disk_rdsect(uptr, lba, buf, §sread, 1); if (r != SCPE_OK) { sim_debug(HA_TRACE, &ha_dev, "[ha_read_block_disk] Could not read block %d\n", lba); - HA_STAT(HA_CKCON, CIO_SUCCESS); + HA_STAT(tc, HA_CKCON, CIO_SUCCESS); return; } for (i = 0; i < HA_BLKSZ; i++) { - pwrite_b(addr + i, buf[i]); + pwrite_b(addr + i, buf[i], BUS_PER); } sim_debug(HA_TRACE, &ha_dev, "[ha_read_block_disk] Transferred 512 bytes to 0x%08x\n", addr); - HA_STAT(HA_GOOD, CIO_SUCCESS); + HA_STAT(tc, HA_GOOD, CIO_SUCCESS); - ha_state.reply.addr = addr; - ha_state.reply.len = HA_BLKSZ; + ha_state.ts[tc].rep.addr = addr; + ha_state.ts[tc].rep.len = HA_BLKSZ; } -static void ha_build_req(uint8 subdev, t_bool express) +static void ha_write_block_disk(UNIT *uptr, uint32 addr, uint8 tc, uint32 lba) { - uint32 i, rqp, ptr, dma_lst; + t_seccnt sectswritten; + t_stat r; + uint8 buf[HA_BLKSZ]; + uint32 i; + + for (i = 0 ; i < HA_BLKSZ; i++) { + buf[i] = pread_b(addr + i, BUS_PER); + } + + r = sim_disk_wrsect(uptr, lba, buf, §swritten, 1); + + if (r != SCPE_OK) { + sim_debug(HA_TRACE, &ha_dev, + "[ha_write_block_disk] Could not write block %d\n", + lba); + HA_STAT(tc, HA_CKCON, CIO_SUCCESS); + return; + } + + HA_STAT(tc, HA_GOOD, CIO_SUCCESS); + + ha_state.ts[tc].rep.addr = addr; + ha_state.ts[tc].rep.len = HA_BLKSZ; +} + +static void ha_build_req(uint8 tc, uint8 subdev, t_bool express) +{ + uint32 i, rqp, ptr, dma_lst, daddr_ptr; uint32 len, addr; cio_entry rqe; uint8 rapp_data[RAPP_LEN] = {0}; @@ -681,40 +637,42 @@ static void ha_build_req(uint8 subdev, t_bool express) */ for (i = 0; i < HA_MAX_CMD; i++) { - ha_state.request.cmd[i] = 0; + ha_state.ts[tc].req.cmd[i] = 0; } if (ha_state.frq) { - rqp = cio[ha_state.cid].rqp; + rqp = cio[ha_state.slot].rqp; - subdev = pread_b(rqp + 2); + subdev = pread_b(rqp + 2, BUS_PER); - ha_state.request.tc = FC_TC(subdev); - ha_state.request.lu = FC_LU(subdev); - ha_state.request.timeout = pread_w(rqp + 4); - ha_state.request.cmd_len = pread_h(rqp + 18); + ha_state.ts[tc].req.tc = FC_TC(subdev); + ha_state.ts[tc].req.lu = FC_LU(subdev); + ha_state.ts[tc].req.timeout = pread_w(rqp + 4, BUS_PER); + ha_state.ts[tc].req.cmd_len = pread_h(rqp + 18, BUS_PER); for (i = 0; i < HA_MAX_CMD; i++) { - ha_state.request.cmd[i] = pread_b(rqp + 20 + i); + ha_state.ts[tc].req.cmd[i] = pread_b(rqp + 20 + i, BUS_PER); } - ha_state.request.op = ha_state.request.cmd[0]; + ha_state.ts[tc].req.op = ha_state.ts[tc].req.cmd[0]; /* Possible list of DMA scatter/gather addresses */ - dma_lst = pread_h(rqp + 16) / 8; + dma_lst = pread_h(rqp + 16, BUS_PER) / 8; if (dma_lst) { t_bool link; /* There's a list of address / lengths. Each entry is 8 * bytes long. */ - ptr = pread_w(rqp + 8); + ptr = pread_w(rqp + 8, BUS_PER); link = FALSE; sim_debug(HA_TRACE, &ha_dev, "[build_req] Building a list of scatter/gather addresses.\n"); + daddr_ptr = 0; + for (i = 0; (i < dma_lst) || link; i++) { - addr = pread_w(ptr); - len = pread_w(ptr + 4); + addr = pread_w(ptr, BUS_PER); + len = pread_w(ptr + 4, BUS_PER); if (len == 0) { sim_debug(HA_TRACE, &ha_dev, @@ -724,7 +682,7 @@ static void ha_build_req(uint8 subdev, t_bool express) if (len > 0x1000) { /* There's a new pointer in town */ - ptr = pread_w(ptr); + ptr = pread_w(ptr, BUS_PER); sim_debug(HA_TRACE, &ha_dev, "[build_req] New ptr=%08x\n", ptr); @@ -734,50 +692,74 @@ static void ha_build_req(uint8 subdev, t_bool express) sim_debug(HA_TRACE, &ha_dev, "[build_req] daddr[%d]: addr=%08x, len=%d (%x)\n", - i, addr, len, len); + daddr_ptr, addr, len, len); - ha_state.request.daddr[i].addr = addr; - ha_state.request.daddr[i].len = len; + ha_state.ts[tc].req.daddr[daddr_ptr].addr = addr; + ha_state.ts[tc].req.daddr[daddr_ptr].len = len; + daddr_ptr++; ptr += 8; } - ha_state.request.dlen = i; + ha_state.ts[tc].req.dlen = i; } else { /* There's only one embedded address / length */ - ha_state.request.daddr[0].addr = pread_w(rqp + 8); - ha_state.request.daddr[0].len = pread_w(rqp + 12); - ha_state.request.dlen = 1; + ha_state.ts[tc].req.daddr[0].addr = pread_w(rqp + 8, BUS_PER); + ha_state.ts[tc].req.daddr[0].len = pread_w(rqp + 12, BUS_PER); + ha_state.ts[tc].req.dlen = 1; } } else { if (express) { - cio_rexpress(ha_state.cid, SCQRESIZE, &rqe, rapp_data); + cio_rexpress(ha_state.slot, SCQRESIZE, &rqe, rapp_data); } else { /* TODO: Find correct queue number! */ - cio_rqueue(ha_state.cid, 0, SCQRESIZE, &rqe, rapp_data); + cio_rqueue(ha_state.slot, 0, SCQRESIZE, &rqe, rapp_data); } ptr = rqe.address; - ha_state.request.tc = FC_TC(rqe.subdevice); - ha_state.request.lu = FC_LU(rqe.subdevice); - ha_state.request.cmd_len = pread_w(ptr + 4); - ha_state.request.timeout = pread_w(ptr + 8); - ha_state.request.daddr[0].addr = pread_w(ptr + 12); - ha_state.request.daddr[0].len = rqe.byte_count; - ha_state.request.dlen = 1; + ha_state.ts[tc].req.tc = FC_TC(rqe.subdevice); + ha_state.ts[tc].req.lu = FC_LU(rqe.subdevice); + ha_state.ts[tc].req.cmd_len = pread_w(ptr + 4, BUS_PER); + ha_state.ts[tc].req.timeout = pread_w(ptr + 8, BUS_PER); + ha_state.ts[tc].req.daddr[0].addr = pread_w(ptr + 12, BUS_PER); + ha_state.ts[tc].req.daddr[0].len = rqe.byte_count; + ha_state.ts[tc].req.dlen = 1; sim_debug(HA_TRACE, &ha_dev, "[build_req] [non-fast] Building a list of 1 scatter/gather addresses.\n"); - ptr = pread_w(ptr); + ptr = pread_w(ptr, BUS_PER); - for (i = 0; (i < ha_state.request.cmd_len) && (i < HA_MAX_CMD); i++) { - ha_state.request.cmd[i] = pread_b(ptr + i); + for (i = 0; (i < ha_state.ts[tc].req.cmd_len) && (i < HA_MAX_CMD); i++) { + ha_state.ts[tc].req.cmd[i] = pread_b(ptr + i, BUS_PER); } - ha_state.request.op = ha_state.request.cmd[0]; + ha_state.ts[tc].req.op = ha_state.ts[tc].req.cmd[0]; + } +} + +static SIM_INLINE void ha_cmd_prep(uint8 tc, uint8 op, uint8 subdev, t_bool express) +{ + ha_state.ts[tc].pending = TRUE; + ha_state.ts[tc].rep.op = op; + ha_state.ts[tc].rep.subdev = subdev; + ha_state.ts[tc].rep.status = CIO_FAILURE; + ha_state.ts[tc].rep.ssb = 0; + ha_state.ts[tc].rep.len = 0; + ha_state.ts[tc].rep.addr = 0; + + if (ha_state.pump_state == PUMP_COMPLETE) { + ha_state.ts[tc].rep.op |= 0x80; + } + + if (ha_state.frq) { + ha_state.ts[tc].rep.type = HA_JOB_QUICK; + } else if (express) { + ha_state.ts[tc].rep.type = HA_JOB_EXPRESS; + } else { + ha_state.ts[tc].rep.type = HA_JOB_FULL; } } @@ -785,30 +767,7 @@ static void ha_cmd(uint8 op, uint8 subdev, uint32 addr, int32 len, t_bool expres { int32 i, block; UNIT *uptr; - int8 target; - - /* Immediately cancel any pending IRQs */ - sim_cancel(cio_unit); - - ha_state.reply.pending = TRUE; - ha_state.reply.op = op; - ha_state.reply.subdev = subdev; - ha_state.reply.status = CIO_FAILURE; - ha_state.reply.ssb = 0; - ha_state.reply.len = 0; - ha_state.reply.addr = 0; - - if (ha_state.pump_state == PUMP_COMPLETE) { - ha_state.reply.op |= 0x80; - } - - if (ha_state.frq) { - ha_state.reply.type = HA_JOB_QUICK; - } else if (express) { - ha_state.reply.type = HA_JOB_EXPRESS; - } else { - ha_state.reply.type = HA_JOB_FULL; - } + uint8 dsd_tc, tc; sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] --------------------------[START]---------------------------------\n"); @@ -816,203 +775,275 @@ static void ha_cmd(uint8 op, uint8 subdev, uint32 addr, int32 len, t_bool expres "[ha_cmd] op=%02x (%d), subdev=%02x, addr=%08x, len=%d\n", op, op, subdev, addr, len); - dump_req(); - switch (op) { case CIO_DLM: + tc = HA_SCSI_ID; + ha_cmd_prep(tc, op, subdev, express); + for (i = 0; i < len; i++) { - ha_crc = cio_crc32_shift(ha_crc, pread_b(addr + i)); + ha_crc = cio_crc32_shift(ha_crc, pread_b(addr + i, BUS_PER)); } sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] SCSI Download Memory: bytecnt=%04x " "addr=%08x return_addr=%08x subdev=%02x (CRC=%08x)\n", len, addr, addr, subdev, ha_crc); - ha_state.reply.status = CIO_SUCCESS; - sim_activate_abs(cio_unit, 1200); + ha_state.ts[tc].rep.status = CIO_SUCCESS; + sim_activate_abs(cio_unit, 1000); break; case CIO_FCF: + tc = HA_SCSI_ID; + ha_cmd_prep(tc, op, subdev, express); + sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] SCSI Force Function Call. (CRC=%08x)\n", ha_crc); - cio[ha_state.cid].sysgen_s = 0; - ha_state.reply.status = CIO_SUCCESS; - sim_activate_abs(cio_unit, 1200); + if (ha_crc == DIAG_CRC_1) { + pwrite_h(0x200f000, 0x1, BUS_PER); /* Test success */ + pwrite_h(0x200f002, 0x0, BUS_PER); /* Test Number */ + pwrite_h(0x200f004, 0x0, BUS_PER); /* Actual */ + pwrite_h(0x200f006, 0x0, BUS_PER); /* Expected */ + pwrite_b(0x200f008, 0x1, BUS_PER); /* Success flag again */ + } + + cio[ha_state.slot].sysgen_s = 0; + ha_state.ts[tc].rep.status = CIO_SUCCESS; + sim_activate_abs(cio_unit, 1000); break; case CIO_DSD: + tc = HA_SCSI_ID; + ha_cmd_prep(tc, op, subdev, express); + sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] SCSI DSD - %d CONFIGURED DEVICES (writing to addr %08x).\n", ha_subdev_cnt, addr); - pwrite_h(addr, ha_subdev_cnt); + pwrite_h(addr, ha_subdev_cnt, BUS_PER); for (i = 0; i < ha_subdev_cnt; i++) { addr += 2; - target = ha_subdev_tab[i]; + dsd_tc = ha_subdev_tab[i]; - if (target < 0) { - pwrite_h(addr, 0); + if (dsd_tc < 0) { + pwrite_h(addr, 0, BUS_PER); continue; } - uptr = &ha_unit[target]; + uptr = &ha_unit[dsd_tc]; sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] [DSD] Probing subdev %d, target %d, devtype %d\n", - i, target, uptr->drvtyp->devtype); + i, dsd_tc, uptr->drvtyp->devtype); switch(uptr->drvtyp->devtype) { case SCSI_DISK: sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] [DSD] Subdev %d is DISK (writing to addr %08x)\n", i, addr); - pwrite_h(addr, HA_DSD_DISK); + pwrite_h(addr, HA_DSD_DISK, BUS_PER); break; case SCSI_TAPE: sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] [DSD] Subdev %d is TAPE (writing to addr %08x)\n", i, addr); - pwrite_h(addr, HA_DSD_TAPE); + pwrite_h(addr, HA_DSD_TAPE, BUS_PER); break; default: sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] [DSD] Warning: No device type for subdev %d (Writing to addr %08x)\n", i, addr); - pwrite_h(addr, 0); + pwrite_h(addr, 0, BUS_PER); break; } } - ha_state.reply.status = CIO_SUCCESS; + ha_state.ts[tc].rep.status = CIO_SUCCESS; - sim_activate_abs(cio_unit, 5000); + sim_activate_abs(cio_unit, 1000); break; case HA_BOOT: - target = ha_subdev_tab[subdev & 7]; + tc = ha_subdev_tab[subdev & 7]; + ha_cmd_prep(tc, op, subdev, express); + sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] TARGET %d BOOTING.\n", - target); + tc); - if (target < 0) { - ha_state.reply.status = CIO_TIMEOUT; - sim_activate_abs(cio_unit, 250); + if (tc < 0) { + ha_state.ts[tc].rep.status = CIO_TIMEOUT; + sim_activate_abs(cio_unit, 1000); return; } - uptr = &ha_unit[target]; + uptr = &ha_unit[tc]; if (!(uptr->flags & UNIT_ATT)) { sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] TARGET %d NOT ATTACHED.\n", - target); - ha_state.reply.status = CIO_TIMEOUT; - sim_activate_abs(cio_unit, 250); + tc); + ha_state.ts[tc].rep.status = CIO_TIMEOUT; + sim_activate_abs(cio_unit, 1000); return; } switch(uptr->drvtyp->devtype) { case SCSI_DISK: - ha_boot_disk(uptr, target); + ha_boot_disk(uptr, tc); break; case SCSI_TAPE: - ha_boot_tape(uptr); + ha_boot_tape(uptr, tc); break; default: sim_debug(HA_TRACE, &ha_dev, "[HA_BOOT] Cannot boot target %d (not disk or tape).\n", - target); - ha_state.reply.status = CIO_SUCCESS; + tc); break; } - sim_activate_abs(cio_unit, 5000); + ha_state.ts[tc].rep.status = CIO_SUCCESS; + sim_activate_abs(cio_unit, 1000); break; case HA_READ_BLK: - target = ha_subdev_tab[subdev & 7]; + tc = ha_subdev_tab[subdev & 7]; + ha_cmd_prep(tc, op, subdev, express); sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] SUBDEV %d TARGET %d READ BLOCK (BLOCK 0x%08x TO ADDR 0x%08x)\n", - subdev, target, pread_w(addr), pread_w(addr + 4)); + subdev, tc, pread_w(addr, BUS_PER), pread_w(addr + 4, BUS_PER)); sim_debug(HA_TRACE, &ha_dev, - "[boot_next] addr = %08x\n", + "[ha_read_blk] addr = %08x\n", addr); sim_debug(HA_TRACE, &ha_dev, - "[boot_next] %08x = %08x\n", - addr, pread_w(addr)); + "[ha_read_blk] %08x = %08x\n", + addr, pread_w(addr, BUS_PER)); sim_debug(HA_TRACE, &ha_dev, - "[boot_next] %08x = %08x\n", - addr + 4, pread_w(addr + 4)); + "[ha_read_blk] %08x = %08x\n", + addr + 4, pread_w(addr + 4, BUS_PER)); sim_debug(HA_TRACE, &ha_dev, - "[boot_next] %08x = %08x\n", - addr + 8, pread_w(addr + 8)); + "[ha_read_blk] %08x = %08x\n", + addr + 8, pread_w(addr + 8, BUS_PER)); sim_debug(HA_TRACE, &ha_dev, - "[boot_next] %08x = %08x\n", - addr + 12, pread_w(addr + 12)); + "[ha_read_blk] %08x = %08x\n", + addr + 12, pread_w(addr + 12, BUS_PER)); sim_debug(HA_TRACE, &ha_dev, - "[boot_next] %08x = %08x\n", - addr + 16, pread_w(addr + 16)); + "[ha_read_blik] %08x = %08x\n", + addr + 16, pread_w(addr + 16, BUS_PER)); - if (target < 0) { - ha_state.reply.status = CIO_TIMEOUT; - sim_activate_abs(cio_unit, 250); + if (tc < 0) { + ha_state.ts[tc].rep.status = CIO_TIMEOUT; + sim_activate_abs(cio_unit, 1000); return; } - uptr = &ha_unit[target]; + uptr = &ha_unit[tc]; if (!(uptr->flags & UNIT_ATT)) { - ha_state.reply.status = CIO_TIMEOUT; - sim_activate_abs(cio_unit, 250); + ha_state.ts[tc].rep.status = CIO_TIMEOUT; + sim_activate_abs(cio_unit, 1000); return; } - block = pread_w(addr); /* Logical block we've been asked to read */ - addr = pread_w(addr + 4); /* Dereference the pointer to the destination */ + block = pread_w(addr, BUS_PER); /* Logical block we've been asked to read */ + addr = pread_w(addr + 4, BUS_PER); /* Dereference the pointer to the destination */ switch(uptr->drvtyp->devtype) { case SCSI_TAPE: - ha_read_block_tape(uptr, addr); + ha_read_block_tape(uptr, addr, tc); break; case SCSI_DISK: - ha_read_block_disk(uptr, target, addr, block); + ha_read_block_disk(uptr, addr, tc, block); break; default: sim_debug(HA_TRACE, &ha_dev, "[HA_READ_BLOCK] Cannot read block %d on target %d (not disk or tape)\n", - block, target); - ha_state.reply.status = CIO_SUCCESS; + block, tc); break; } - sim_activate_abs(cio_unit, 5000); + ha_state.ts[tc].rep.status = CIO_SUCCESS; + sim_activate_abs(cio_unit, 1000); + break; + case HA_WRITE_BLK: + tc = ha_subdev_tab[subdev & 7]; + ha_cmd_prep(tc, op, subdev, express); + + sim_debug(HA_TRACE, &ha_dev, + "[ha_cmd] SUBDEV %d TARGET %d WRITE BLOCK (BLOCK 0x%08x FROM ADDR 0x%08x)\n", + subdev, tc, pread_w(addr, BUS_PER), pread_w(addr + 4, BUS_PER)); + + sim_debug(HA_TRACE, &ha_dev, + "[ha_write_blk] addr = %08x\n", + addr); + sim_debug(HA_TRACE, &ha_dev, + "[ha_write_blk] %08x = %08x\n", + addr, pread_w(addr, BUS_PER)); + sim_debug(HA_TRACE, &ha_dev, + "[ha_write_blk] %08x = %08x\n", + addr + 4, pread_w(addr + 4, BUS_PER)); + + if (tc < 0) { + ha_state.ts[tc].rep.status = CIO_TIMEOUT; + sim_activate_abs(cio_unit, 1000); + return; + } + + uptr = &ha_unit[tc]; + + if (!(uptr->flags & UNIT_ATT)) { + ha_state.ts[tc].rep.status = CIO_TIMEOUT; + sim_activate_abs(cio_unit, 1000); + return; + } + + block = pread_w(addr, BUS_PER); /* Logical block we've been asked to write */ + addr = pread_w(addr + 4, BUS_PER); /* Dereference the pointer to the source */ + + switch(uptr->drvtyp->devtype) { + case SCSI_DISK: + ha_write_block_disk(uptr, addr, tc, block); + break; + default: + sim_debug(HA_TRACE, &ha_dev, + "[ha_write_blk] Cannot write block %d on target %d (not disk)\n", + block, tc); + break; + } + + ha_state.ts[tc].rep.status = CIO_SUCCESS; + sim_activate_abs(cio_unit, 1000); break; case HA_CNTRL: + tc = FC_TC(subdev); + ha_cmd_prep(tc, op, subdev, express); + sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] SCSI CONTROL (subdev=%02x addr=%08x)\n", subdev, addr); - ha_build_req(subdev, express); - ha_ctrl(); + ha_build_req(tc, subdev, express); + ha_ctrl(tc); sim_activate_abs(cio_unit, 1000); break; case HA_VERS: /* * Get Host Adapter Version */ + tc = HA_SCSI_ID; + ha_cmd_prep(tc, op, subdev, express); sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] SCSI GET VERSION (addr=%08x len=%08x)\n", addr, len); - pwrite_w(addr, HA_VERSION); - ha_state.reply.status = CIO_SUCCESS; - sim_activate_abs(cio_unit, 5000); + pwrite_w(addr, HA_VERSION, BUS_PER); + ha_state.ts[tc].rep.status = CIO_SUCCESS; + sim_activate_abs(cio_unit, 1000); break; case HA_DL_EEDT: @@ -1020,18 +1051,20 @@ static void ha_cmd(uint8 op, uint8 subdev, uint32 addr, int32 len, t_bool expres * This is a request to download the Extended Equipped Device * Table from the host adapter to the 3B2 main memory. */ + tc = HA_SCSI_ID; + ha_cmd_prep(tc, op, subdev, express); sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] SCSI DOWNLOAD EDT (%d bytes to address %08x)\n", len, addr); for (i = 0; i < len; i++) { - pwrite_b(addr + i, ha_state.edt[i]); + pwrite_b(addr + i, ha_state.edt[i], BUS_PER); } - ha_state.reply.status = CIO_SUCCESS; + ha_state.ts[tc].rep.status = CIO_SUCCESS; - sim_activate_abs(cio_unit, 5000); + sim_activate_abs(cio_unit, 1000); break; case HA_UL_EEDT: @@ -1040,63 +1073,87 @@ static void ha_cmd(uint8 op, uint8 subdev, uint32 addr, int32 len, t_bool expres * Table from the 3B2 main memory to the host adapter */ + tc = HA_SCSI_ID; + ha_cmd_prep(tc, op, subdev, express); + sim_debug(HA_TRACE, &ha_dev, "[ha_cmd] SCSI UPLOAD EDT (%d bytes from address %08x)\n", len, addr); for (i = 0; i < len; i++) { - ha_state.edt[i] = pread_b(addr + i); + ha_state.edt[i] = pread_b(addr + i, BUS_PER); } - ha_state.reply.status = CIO_SUCCESS; + ha_state.ts[tc].rep.status = CIO_SUCCESS; - sim_activate_abs(cio_unit, 5000); + sim_activate_abs(cio_unit, 1000); break; case HA_EDSD: /* * This command is used to determine which TCs are attached to - * the SCSI bus, and what LUNs they support. A "1" in a slot - * means that the target is not a direct block device. Since we - * only support direct block devices, we just put "0" in each - * slot. + * the SCSI bus, and what LUNs they support. */ + tc = HA_SCSI_ID; + ha_cmd_prep(tc, op, subdev, express); sim_debug(HA_TRACE, &ha_dev, - "[%08x] [ha_cmd] SCSI EXTENDED DSD.\n", - R[NUM_PC]); + "[ha_cmd] SCSI EXTENDED DSD.\n"); - ha_state.reply.status = CIO_SUCCESS; - ha_state.reply.addr = addr; - ha_state.reply.len = 9; + ha_state.ts[tc].rep.status = CIO_SUCCESS; + ha_state.ts[tc].rep.addr = addr; + ha_state.ts[tc].rep.len = 9; + /* + * Loop over each SCSI ID and configure LUNs. + */ for (i = 0; i < 8; i++) { uptr = &ha_unit[i]; - pwrite_b(addr + i, (uptr->flags & UNIT_ATT) ? 1 : 0); + /* + * TODO: The byte being written here is a bit mask of + * equipped luns. e.g., + * + * - 0x01 means LUN 0 is equipped, + * - 0x80 means LUN 7 is equipped, + * - 0x33 means LUNs 0, 1, 4, and 5 are equipped. + * + * For now, we only support one LUN per target, and it's + * always LUN 0. + */ + pwrite_b(addr + i, (uptr->flags & UNIT_ATT) ? 1 : 0, BUS_PER); } - pwrite_b(addr + 8, HA_SCSI_ID); /* ID of the card */ + pwrite_b(addr + 8, HA_SCSI_ID, BUS_PER); /* ID of the card */ - sim_activate_abs(cio_unit, 200); + sim_activate_abs(cio_unit, 1000); break; - case 0x45: + case HA_RESET: + tc = HA_SCSI_ID; + ha_cmd_prep(tc, op, subdev, express); + scsi_reset(&ha_bus); - ha_state.reply.status = CIO_SUCCESS; - ha_state.reply.addr = addr; - ha_state.reply.len = 0; + sim_debug(HA_TRACE, &ha_dev, + "[ha_cmd] SCSI RESET.\n"); - sim_activate_abs(cio_unit, 2500); + ha_state.ts[tc].rep.status = CIO_SUCCESS; + ha_state.ts[tc].rep.addr = addr; + ha_state.ts[tc].rep.len = 0; + + sim_activate_abs(cio_unit, 1000); break; default: + tc = HA_SCSI_ID; + ha_cmd_prep(tc, op, subdev, express); + sim_debug(HA_TRACE, &ha_dev, - "[%08x] *** SCSI WARNING: UNHANDLED OPCODE 0x%02x\n", - R[NUM_PC], op); + "*** SCSI WARNING: UNHANDLED OPCODE 0x%02x\n", + op); - ha_state.reply.status = CIO_FAILURE; + ha_state.ts[tc].rep.status = CIO_FAILURE; - sim_activate_abs(cio_unit, 200); + sim_activate_abs(cio_unit, 1000); } sim_debug(HA_TRACE, &ha_dev, @@ -1107,7 +1164,7 @@ static void ha_cmd(uint8 op, uint8 subdev, uint32 addr, int32 len, t_bool expres /* * Handle a raw SCSI control message. */ -void ha_ctrl() +void ha_ctrl(uint8 tc) { volatile t_bool txn_done; uint32 i, j; @@ -1120,63 +1177,74 @@ void ha_ctrl() sim_debug(HA_TRACE, &ha_dev, "[ha_ctrl] [HA_REQ] TC=%d LU=%d TIMEOUT=%d DLEN=%d\n", - ha_state.request.tc, ha_state.request.lu, ha_state.request.timeout, ha_state.request.dlen); + ha_state.ts[tc].req.tc, + ha_state.ts[tc].req.lu, + ha_state.ts[tc].req.timeout, + ha_state.ts[tc].req.dlen); sim_debug(HA_TRACE, &ha_dev, "[ha_ctrl] [HA_REQ] CMD_LEN=%d CMD=<%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x>\n", - ha_state.request.cmd_len, - ha_state.request.cmd[0], ha_state.request.cmd[1], - ha_state.request.cmd[2], ha_state.request.cmd[3], - ha_state.request.cmd[4], ha_state.request.cmd[5], - ha_state.request.cmd[6], ha_state.request.cmd[7], - ha_state.request.cmd[8], ha_state.request.cmd[9]); + ha_state.ts[tc].req.cmd_len, + ha_state.ts[tc].req.cmd[0], ha_state.ts[tc].req.cmd[1], + ha_state.ts[tc].req.cmd[2], ha_state.ts[tc].req.cmd[3], + ha_state.ts[tc].req.cmd[4], ha_state.ts[tc].req.cmd[5], + ha_state.ts[tc].req.cmd[6], ha_state.ts[tc].req.cmd[7], + ha_state.ts[tc].req.cmd[8], ha_state.ts[tc].req.cmd[9]); in_len = out_len = 0; /* * These ops need special handling. */ - switch(ha_state.request.op) { + switch(ha_state.ts[tc].req.op) { case HA_TESTRDY: /* Fail early if LU is set */ - if (ha_state.request.lu) { - HA_STAT(HA_CKCON, CIO_TIMEOUT); + if (ha_state.ts[tc].req.lu) { + HA_STAT(tc, HA_CKCON, CIO_TIMEOUT); return; } break; case HA_FORMAT: /* Not yet handled by sim_scsi library */ case HA_VERIFY: /* Not yet handled by sim_scsi library */ /* Just mimic success */ - HA_STAT(HA_GOOD, CIO_SUCCESS); + HA_STAT(tc, HA_GOOD, CIO_SUCCESS); return; } /* Get the bus's attention */ if (!scsi_arbitrate(&ha_bus, HA_SCSI_ID)) { - HA_STAT(HA_CKCON, CIO_TIMEOUT); + HA_STAT(tc, HA_CKCON, CIO_TIMEOUT); return; } scsi_set_atn(&ha_bus); - if (!scsi_select(&ha_bus, ha_state.request.tc)) { - HA_STAT(HA_CKCON, CIO_TIMEOUT); + if (!scsi_select(&ha_bus, ha_state.ts[tc].req.tc)) { + HA_STAT(tc, HA_CKCON, CIO_TIMEOUT); scsi_release(&ha_bus); return; } /* Select the correct LU */ - lu = 0x80 | ha_state.request.lu; + lu = 0x80 | ha_state.ts[tc].req.lu; scsi_write(&ha_bus, &lu, 1); txn_done = FALSE; + /* TODO: Fix this. Work around a bug in command length. The host + * occasionally sends a command length of 8 for 6-byte SCSI + * commands. The sim_scsi library knows to only consume 6 bytes, + * which leaves the buffer in a bad state. */ + if (ha_state.ts[tc].req.cmd_len == 8) { + ha_state.ts[tc].req.cmd_len = 6; + } + while (!txn_done) { switch(ha_bus.phase) { case SCSI_CMD: - plen = scsi_write(&ha_bus, ha_state.request.cmd, ha_state.request.cmd_len); - if (plen < ha_state.request.cmd_len) { - HA_STAT(HA_CKCON, CIO_SUCCESS); + plen = scsi_write(&ha_bus, ha_state.ts[tc].req.cmd, ha_state.ts[tc].req.cmd_len); + if (plen < ha_state.ts[tc].req.cmd_len) { + HA_STAT(tc, HA_CKCON, CIO_SUCCESS); scsi_release(&ha_bus); return; } @@ -1190,25 +1258,29 @@ void ha_ctrl() in_len, in_len); /* We need special handling based on the op code */ - switch(ha_state.request.op) { + switch(ha_state.ts[tc].req.op) { case HA_READ: case HA_READEXT: ha_ptr = 0; - for (i = 0; i < ha_state.request.dlen; i++) { + for (i = 0; i < ha_state.ts[tc].req.dlen; i++) { /* * Consume the lesser of: * - The total bytes we consumed, or: * - The length of the current block */ - to_read = MIN(ha_state.request.daddr[i].len, in_len); + to_read = MIN(ha_state.ts[tc].req.daddr[i].len, in_len); sim_debug(HA_TRACE, &ha_dev, "[(%02x) TC%d,LU%d] DATI: Processing %d bytes to address %08x...\n", - ha_state.request.op, ha_state.request.tc, ha_state.request.lu, to_read, ha_state.request.daddr[i].addr); + ha_state.ts[tc].req.op, + ha_state.ts[tc].req.tc, + ha_state.ts[tc].req.lu, + to_read, + ha_state.ts[tc].req.daddr[i].addr); for (j = 0; j < to_read; j++) { - pwrite_b(ha_state.request.daddr[i].addr + j, ha_buf[ha_ptr++]); + pwrite_b(ha_state.ts[tc].req.daddr[i].addr + j, ha_buf[ha_ptr++], BUS_PER); } if (in_len >= to_read) { @@ -1223,12 +1295,12 @@ void ha_ctrl() default: sim_debug(HA_TRACE, &ha_dev, "[(%02x) TC%d,LU%d] DATI: Processing %d bytes to address %08x...\n", - ha_state.request.op, ha_state.request.tc, - ha_state.request.lu, in_len, - ha_state.request.daddr[0].addr); + ha_state.ts[tc].req.op, ha_state.ts[tc].req.tc, + ha_state.ts[tc].req.lu, in_len, + ha_state.ts[tc].req.daddr[0].addr); for (i = 0; i < in_len; i++) { sim_debug(HA_TRACE, &ha_dev, "[%04x] [DATI] 0x%02x\n", i, ha_buf[i]); - pwrite_b(ha_state.request.daddr[0].addr + i, ha_buf[i]); + pwrite_b(ha_state.ts[tc].req.daddr[0].addr + i, ha_buf[i], BUS_PER); } break; @@ -1239,21 +1311,26 @@ void ha_ctrl() /* This is a write */ ha_ptr = 0; out_len = 0; - ha_state.reply.len = ha_state.request.dlen; + ha_state.ts[tc].rep.len = ha_state.ts[tc].req.dlen; - for (i = 0; i < ha_state.request.dlen; i++) { + for (i = 0; i < ha_state.ts[tc].req.dlen; i++) { sim_debug(HA_TRACE, &ha_dev, "[ha_ctrl] [%d] DATO: Writing %d bytes to ha_buf.\n", - i, ha_state.request.daddr[i].len); + i, ha_state.ts[tc].req.daddr[i].len); - for (j = 0; j < ha_state.request.daddr[i].len; j++) { - ha_buf[ha_ptr++] = pread_b(ha_state.request.daddr[i].addr + j); + for (j = 0; j < ha_state.ts[tc].req.daddr[i].len; j++) { + ha_buf[ha_ptr++] = pread_b(ha_state.ts[tc].req.daddr[i].addr + j, BUS_PER); + if (ha_state.ts[tc].req.op == 0x15) { + sim_debug(HA_TRACE, &ha_dev, + "[ha_ctrl] [%d]\t\t%02x\n", + j, ha_buf[ha_ptr - 1]); + } } - out_len += ha_state.request.daddr[i].len; + out_len += ha_state.ts[tc].req.daddr[i].len; } - if (ha_state.request.op == HA_WRITE || ha_state.request.op == HA_WRTEXT) { + if (ha_state.ts[tc].req.op == HA_WRITE || ha_state.ts[tc].req.op == HA_WRTEXT) { /* If total len is not on a block boundary, we have to bump it up in order to write the whole block. */ if (out_len % HA_BLKSZ) { @@ -1290,38 +1367,39 @@ void ha_ctrl() } } - if (ha_bus.sense_info) { - sim_debug(HA_TRACE, &ha_dev, "[ha_ctrl] SENSE INFO=%d, CKCON.\n", ha_bus.sense_info); - HA_STAT(HA_CKCON, 0x60); + if (ha_bus.sense_key || ha_bus.sense_code) { + sim_debug(HA_TRACE, &ha_dev, + "[ha_ctrl] SENSE KEY=%d CODE=%d INFO=%d, CKCON.\n", + ha_bus.sense_key, ha_bus.sense_code, ha_bus.sense_info); + HA_STAT(tc, HA_CKCON, 0x60); } else { sim_debug(HA_TRACE, &ha_dev, "[ha_ctrl] NO SENSE INFO.\n"); - HA_STAT(HA_GOOD, CIO_SUCCESS); + HA_STAT(tc, HA_GOOD, CIO_SUCCESS); } /* Release the bus */ scsi_release(&ha_bus); } -void ha_fcm_express() +void ha_fcm_express(uint8 tc) { - uint32 rqp, cqp, cqs; + uint32 cqp, cqs; - rqp = cio[ha_state.cid].rqp; - cqp = cio[ha_state.cid].cqp; - cqs = cio[ha_state.cid].cqs; + cqp = cio[ha_state.slot].cqp; + cqs = cio[ha_state.slot].cqs; /* Write the fast completion entry. */ - pwrite_b(cqp + cq_offset, ha_state.reply.status); - pwrite_b(cqp + cq_offset + 1, ha_state.reply.op); - pwrite_b(cqp + cq_offset + 2, ha_state.reply.subdev); - pwrite_b(cqp + cq_offset + 3, ha_state.reply.ssb); + pwrite_b(cqp + cq_offset, ha_state.ts[tc].rep.status, BUS_PER); + pwrite_b(cqp + cq_offset + 1, ha_state.ts[tc].rep.op, BUS_PER); + pwrite_b(cqp + cq_offset + 2, ha_state.ts[tc].rep.subdev, BUS_PER); + pwrite_b(cqp + cq_offset + 3, ha_state.ts[tc].rep.ssb, BUS_PER); sim_debug(HA_TRACE, &ha_dev, "[ha_fcm_express] stat=%02x, op=%02x (%d), cq_index=%d target=%d, lun=%d, ssb=%02x\n", - ha_state.reply.status, ha_state.reply.op, ha_state.reply.op, + ha_state.ts[tc].rep.status, ha_state.ts[tc].rep.op, ha_state.ts[tc].rep.op, (cq_offset / 4), - FC_TC(ha_state.reply.subdev), FC_LU(ha_state.reply.subdev), - ha_state.reply.ssb); + FC_TC(ha_state.ts[tc].rep.subdev), FC_LU(ha_state.ts[tc].rep.subdev), + ha_state.ts[tc].rep.ssb); if (ha_state.pump_state == PUMP_COMPLETE && cqs > 0) { cq_offset = (cq_offset + 4) % (cqs * 4); @@ -1330,104 +1408,3 @@ void ha_fcm_express() } } -/* Used for debugging only */ -/* TODO: Remove after testing */ -static void dump_edt() -{ - uint8 tc_size, lu_size, num_tc, num_lu, i, j; - - uint32 offset; - - char name[11]; - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] Sanity: %08x\n", - ATOW(ha_state.edt, 0)); - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] Version: %d\n", - ha_state.edt[4]); - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] Slot: %d\n", - ha_state.edt[5]); - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] Max TC: %d\n", - ha_state.edt[6]); - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] TC Size: %d\n", - ha_state.edt[7]); - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] Max LUs: %d\n", - ha_state.edt[8]); - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] LU Size: %d\n", - ha_state.edt[9]); - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] Equipped TCs: %d\n", - ha_state.edt[10]); - - tc_size = ha_state.edt[7]; - lu_size = ha_state.edt[9]; - num_tc = ha_state.edt[10] + 1; - - for (i = 0; i < num_tc; i++) { - offset = 12 + (tc_size * i); - num_lu = ha_state.edt[offset + 17]; - - strncpy(name, ((const char *)ha_state.edt + offset + 4), 10); - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] -------------------------\n"); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d] Major Number: %d\n", - i, ATOW(ha_state.edt, offset)); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d] Name: %s\n", - i, name); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d] Type: %d\n", - i, ATOH(ha_state.edt, offset + 14)); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d] Equipped?: %d\n", - i, ha_state.edt[offset + 16]); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d] Equipped LUs: %d\n", - i, ha_state.edt[offset + 17]); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d] Maximum LUs: %d\n", - i, ha_state.edt[offset + 18]); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d] LU Index: %04x\n", - i, ATOH(ha_state.edt, offset + 20)); - - offset = ATOH(ha_state.edt, offset + 20); - - for (j = 0; j < num_lu; j++) { - - offset = offset + (j * lu_size); - - sim_debug(HA_TRACE, &ha_dev, - "[EDT] -------------------------\n"); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d,LU%d] LU #: %d\n", - i, j, ha_state.edt[offset]); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d,LU%d] PD Type: 0x%02x\n", - i, j, ha_state.edt[offset + 1]); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d,LU%d] Dev Type: 0x%02x\n", - i, j, ha_state.edt[offset + 2] >> 1); - sim_debug(HA_TRACE, &ha_dev, - "[EDT] [TC%d,LU%d] Removable?: %d\n", - i, j, ha_state.edt[offset + 2] & 1); - } - - } - -} diff --git a/3B2/3b2_scsi.h b/3B2/3b2_scsi.h index e8b99a9d..2a3ffb80 100644 --- a/3B2/3b2_scsi.h +++ b/3B2/3b2_scsi.h @@ -1,6 +1,6 @@ -/* 3b2_scsi.h: AT&T 3B2 SCSI (CM195W) Host Adapter +/* 3b2_scsi.h: CM195W SCSI Controller CIO Card - Copyright (c) 2020, Seth J. Morabito + Copyright (c) 2020-2022, Seth J. Morabito Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -36,6 +36,7 @@ /* CIO Opcodes */ #define HA_BOOT 0x0a #define HA_READ_BLK 0x0b +#define HA_WRITE_BLK 0x0c #define HA_CNTRL 0x20 #define HA_VERS 0x40 #define HA_DL_EEDT 0x42 @@ -47,6 +48,7 @@ #define HA_FORMAT 0x04 #define HA_WRITE 0x0a #define HA_INQUIRY 0x12 +#define HA_MODESEL 0x15 #define HA_MODESNS 0x1a #define HA_RDCPCTY 0x25 #define HA_READ 0x08 @@ -88,93 +90,116 @@ #define HA_MAX_CMD 12 #define INQUIRY_MAX 36 -#define HA_STAT(ha_stat,cio_stat) { \ - ha_state.reply.ssb = (ha_stat); \ - ha_state.reply.status = (cio_stat); \ +#define HA_STAT(tc,ha_stat,cio_stat) { \ + ha_state.ts[tc].rep.ssb = (ha_stat); \ + ha_state.ts[tc].rep.status = (cio_stat); \ } +/* Hardware Notes + * ============== + * + * Disk Drives + * ----------- + * + * There are two emulated SCSI disk drives available. + * + * 1. 155 MB CDC Wren III (CDC 94161-9) + * 2. 327 MB CDC Wren IV (CDC 94171-9) + * + * The CDC 94161-9 was also OEMed as the "AT&T KS23483,L3" + * The CDC 94171-9 was also OEMed as the "AT&T KS23483,L25" + * + * + * Tape Drive + * ---------- + * + * Wangtek 5125EN (AT&T Part number KS23417,L2) + * + * DC600A cartridge tape at 120MB (QIC-120 format) + * + */ -/* CDC Wren IV 327 MB Hard Disk (AT&T KS-23483,L3) */ -#define SD327_PQUAL 0x00 -#define SD327_SCSI 1 -#define SD327_BLK 512 -#define SD327_LBN 640396 -#define SD327_TEXT "Set CDC 327MB Disk Type" -#define SD327_MANU "AT&T" -#define SD327_DESC "KS23483" -#define SD327_REV "0001" /* TODO: Find real rev */ -#define SD327_TPZ 9 -#define SD327_ASEC 3 -#define SD327_ATPZ 0 -#define SD327_ATPU 0 -#define SD327_SPT 46 -#define SD327_CYL 1549 -#define SD327_HEADS 9 -#define SD327_PREC 1200 -#define SD327_RWC 1200 -#define SD327_STEP 15 -#define SD327_LZ 1549 -#define SD327_RPM 3600 -/* Wangtek 120MB cartridge tape (AT&T KS-23465) */ +/* Other SCSI hard disk types + * --------------------------- + * + * These geometries are supported natively and automatically + * by System V Release 3.2.3 UNIX. + * + * 1. CDC 94161-9 155 MB/148 MiB 512 B/s, 35 s/t, 9 head, 965 cyl + * 2. AT&T KS23483 327 MB/312 MiB 512 B/s, 46 s/t, 9 head, 1547 cyl + * (a.k.a CDC 94171-9) + * + * Also supported was a SCSI-to-ESDI bridge controller that used the + * Emulex MD23/S2 SCSI-to-ESDI bridge. It allowed up to four ESDI + * drives to be mapped as LUNs 0-3. + * + */ + +/* AT&T 155 MB Hard Disk (35 sec/t, 9 hd, 964 cyl) */ +#define SD155_PQUAL 0x00 +#define SD155_SCSI 1 +#define SD155_BLK 512 +#define SD155_LBN 303660 +#define SD155_TEXT "Set 155MB Disk Type" +#define SD155_MANU "AT&T" +#define SD155_DESC "KS23483" +#define SD155_REV "0000" + +/* AT&T 300 MB Hard Disk (43 sec/t, 9 hd, 1514 cyl) */ +#define SD300_PQUAL 0x00 +#define SD300_SCSI 1 +#define SD300_BLK 512 +#define SD300_LBN 585937 +#define SD300_TEXT "Set 300MB Disk Type" +#define SD300_MANU "AT&T" +#define SD300_DESC "KS23483" +#define SD300_REV "0000" + +/* AT&T 327 MB Hard Disk (46 sec/t, 9 hd, 1547 cyl) */ +#define SD327_PQUAL 0x00 +#define SD327_SCSI 1 +#define SD327_BLK 512 +#define SD327_LBN 640458 +#define SD327_TEXT "Set 327MB Disk Type" +#define SD327_MANU "AT&T" +#define SD327_DESC "KS23483" +#define SD327_REV "0000" + +/* AT&T 630 MB Hard Disk (56 sec/t, 16 hd, 1447 cyl) */ +#define SD630_PQUAL 0x00 +#define SD630_SCSI 1 +#define SD630_BLK 512 +#define SD630_LBN 1296512 +#define SD630_TEXT "Set 630MB Disk Type" +#define SD630_MANU "AT&T" +#define SD630_DESC "KS23483" +#define SD630_REV "0000" + +/* Wangtek 120MB cartridge tape */ #define ST120_PQUAL 0x00 #define ST120_SCSI 1 #define ST120_BLK 512 -#define ST120_LBN 266004 +#define ST120_LBN 1 #define ST120_TEXT "Set Wangtek 120MB Tape Type" #define ST120_MANU "WANGTEK" #define ST120_DESC "KS23465" #define ST120_REV "CX17" -#define ST120_DENS 5 #define HA_DISK(d) { DRV_SCSI( \ SCSI_DISK, d##_PQUAL, d##_SCSI, FALSE, d##_BLK, \ d##_LBN, d##_MANU, d##_DESC, d##_REV, #d, 0, \ d##_TEXT) \ } + #define HA_TAPE(d) { DRV_SCSI( \ SCSI_TAPE, d##_PQUAL, d##_SCSI, TRUE, d##_BLK, \ d##_LBN, d##_MANU, d##_DESC, d##_REV, #d, 0, \ d##_TEXT) \ } + #define HA_SIZE(d) d##_LBN - -/* Hardware Notes - * ============== - * - * Disk Drive - * ---------- - * - * We emulate a 300-Megabyte Hard Disk, AT&T part number KS23483,L3. - * - * This is the same as a CDC/Imprimis Wren IV 94171-327 - * - * 512 bytes per block - * 1,520 cylinders - * 2 alternate cylinders (1518 available) - * 46 Sectors per Track - * 3 Alternate Sectors per Track (43 available) - * 9 tracks per cylinder (9 heads) - * - * Formatted Size: 587,466 blocks - * - * - * Tape Drive - * ---------- - * - * Wangtek 5099EN (AT&T Part number KS23417,L2) - * - * DC600A cartridge tape - * - * 512 bytes per block - * 9 tracks - * 13,956 blocks per track - * - * Formatted Size: 125,604 blocks - * - */ - #define HA_JOB_QUICK 0 #define HA_JOB_EXPRESS 1 #define HA_JOB_FULL 2 @@ -208,7 +233,6 @@ typedef struct { */ typedef struct { ha_jobtype type; /* Job type */ - t_bool pending; /* Pending or completed? */ uint8 status; /* Result Status */ uint8 op; /* Command Opcode */ uint8 subdev; /* XXTTTLLL; T=Target, L=LUN */ @@ -221,19 +245,24 @@ typedef struct { #define PUMP_SYSGEN 1 #define PUMP_COMPLETE 2 +/* + * SCSI Target state + */ +typedef struct { + t_bool pending; /* Service pending */ + ha_req req; /* SCSI job request */ + ha_resp rep; /* SCSI job reply */ +} ha_ts; + /* * General SCSI HA internal state. */ typedef struct { - uint8 cid; /* Card Backsplane Slot # */ + uint8 slot; /* Card Backsplane Slot # */ uint32 pump_state; - uint32 haddr; /* Host address for read/write */ - uint32 hlen; /* Length for read or write */ - t_bool initialized; /* Card has been initialized */ - t_bool frq; /* Fast Request Queue enabled */ - uint8 edt[HA_EDT_LEN]; /* Equipped Device Table */ - ha_req request; /* Current job request */ - ha_resp reply; /* Current job reply */ + t_bool frq; /* Fast Request Queue enabled */ + uint8 edt[HA_EDT_LEN]; /* Equipped Device Table */ + ha_ts ts[8]; /* Target state */ } HA_STATE; t_stat ha_show_type(FILE *st, UNIT *uptr, int32 val, CONST void *desc); @@ -245,12 +274,12 @@ t_stat ha_attach(UNIT *uptr, CONST char *cptr); t_stat ha_detach(UNIT *uptr); void ha_fast_queue_check(); -void ha_sysgen(uint8 cid); -void ha_express(uint8 cid); -void ha_full(uint8 cid); +void ha_sysgen(uint8 slot); +void ha_express(uint8 slot); +void ha_full(uint8 slot); /* Fast Completion */ -void ha_fcm_express(); +void ha_fcm_express(uint8 target); #endif /* _3B2_SCSI_H_ */