blob: 362c1e25693805b4bd9fa76aedb51b1f4ac11857 [file] [log] [blame] [raw]
/* sigma_dp.c: moving head disk pack controller
Copyright (c) 2008-2017, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
dp moving head disk pack controller
13-Mar-17 RMS Fixed bug in selecting 3281 unit F (COVERITY)
Transfers are always done a sector at a time.
This module simulates five Sigma controller/disk pack pairs (7240, 7270;
7260, 7265, 7275) and one Telefile controller that supported different
disk models on the same controller (T3281/3282/3283/3286/3288). Due to
ambiguities in the documentation, the T3286 disk is not implemented.
Broadly speaking, the controllers fall into two families: the 7240/7270,
which returned 10 bytes for sense status; and the others, which returned
16 bytes. Each disk has two units: one for timing channel operations, and
one for timing asynchronous seek completions. The controller will not
start a new operation is it is busy (any of the main units active) or if
the target device is busy (its seek unit is active).
*/
#include "sigma_io_defs.h"
#include <math.h>
#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */
#define UNIT_HWLK (1u << UNIT_V_HWLK)
#define UNIT_WPRT (UNIT_HWLK|UNIT_RO) /* write prot */
#define UNIT_V_AUTO (UNIT_V_UF + 1) /* autosize */
#define UNIT_AUTO (1u << UNIT_V_AUTO)
#define UNIT_V_DTYPE (UNIT_V_UF + 2) /* drive type */
#define UNIT_M_DTYPE 0xF
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
#define UDA u3 /* disk addr */
#define UCMD u4 /* current command */
#define UCTX u5 /* ctrl/ctx index */
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
/* Constants */
#define DP_NUMCTL 2 /* number of controllers */
#define DP_CTYPE 6 /* total ctrl types */
#define DP_C7240 0 /* 7240 ctrl */
#define DP_C7270 1 /* 7270 ctrl */
#define DP_C7260 2 /* 7260 ctrl */
#define DP_C7265 3 /* 7265 ctrl */
#define DP_C7275 4 /* 7275 ctrl */
#define DP_C3281 5 /* T3281 ctrl */
#define DP_Q10B(x) ((x) <= DP_C7270) /* 10B or 16B? */
#define DP_NUMDR_10B 8 /* drives/ctrl */
#define DP_NUMDR_16B 15
#define DP_CONT 0xF /* ctrl's drive # */
#define DP_WDSC 256 /* words/sector */
#define DP_BYHD 8 /* byte/header */
#define DP_NUMDR ((uint32) ((DP_Q10B (ctx->dp_ctype))? DP_NUMDR_10B: DP_NUMDR_16B))
#define DP_SEEK (DP_CONT) /* offset to seek units */
/* Address bytes */
#define DPA_V_CY 16 /* cylinder offset */
#define DPA_M_CY 0x3FF
#define DPA_V_HD 8 /* head offset */
#define DPA_M_HD 0x1F
#define DPA_V_SC 0 /* sector offset */
#define DPA_M_SC 0x1F
#define DPA_GETCY(x) (((x) >> DPA_V_CY) & DPA_M_CY)
#define DPA_GETHD(x) (((x) >> DPA_V_HD) & DPA_M_HD)
#define DPA_GETSC(x) (((x) >> DPA_V_SC) & DPA_M_SC)
/* Sense order */
#define DPS_NBY_10B 10
#define DPS_NBY_16B 16
#define DPS_NBY ((uint32) (DP_Q10B (ctx->dp_ctype)? DPS_NBY_10B: DPS_NBY_16B))
/* Test mode */
#define DPT_NBY_10B 1 /* bytes/test mode spec */
#define DPT_NBY_16B 2
#define DPT_NBY ((uint32) (DP_Q10B (ctx->dp_ctype)? DPT_NBY_10B: DPT_NBY_16B))
/* Commands */
#define DPS_INIT 0x100
#define DPS_END 0x101
#define DPS_WRITE 0x01
#define DPS_READ 0x02
#define DPS_SEEK 0x03
#define DPS_SEEKI 0x83
#define DPS_SENSE 0x04
#define DPS_CHECK 0x05
#define DPS_RSRV 0x07
#define DPS_WHDR 0x09
#define DPS_RHDR 0x0A
#define DPS_CRIOF 0x0F
#define DPS_RDEES 0x12
#define DPS_TEST 0x13
#define DPS_RLS 0x17
#define DPS_CRION 0x1F
#define DPS_RLSA 0x23
#define DPS_RECAL 0x33
#define DPS_RECALI 0xB3
/* Seek completion states */
#define DSC_SEEK 0x00 /* seeking */
#define DSC_SEEKI 0x80 /* seeking, then int */
#define DSC_SEEKW 0x01 /* waiting to int */
/* Device status - note that these are device independent */
#define DPF_V_WCHK 0
#define DPF_V_DPE 1
#define DPF_V_SNZ 2
#define DPF_V_EOC 3
#define DPF_V_IVA 4
#define DPF_V_PGE 5
#define DPF_V_WPE 6
#define DPF_V_AIM 7
#define DPF_WCHK (1u << DPF_V_WCHK) /* wrt chk error */
#define DPF_DPE (1u << DPF_V_DPE) /* data error */
#define DPF_SNZ (1u << DPF_V_SNZ) /* sec# != 0 @ whdr */
#define DPF_EOC (1u << DPF_V_EOC) /* end cylinder */
#define DPF_IVA (1u << DPF_V_IVA) /* invalid addr */
#define DPF_PGE (1u << DPF_V_PGE) /* prog error */
#define DPF_WPE (1u << DPF_V_WPE) /* wrt prot err */
#define DPF_AIM (1u << DPF_V_AIM) /* arm in motion */
#define DPF_V_DIFF 16
#define DPF_M_DIFF 0xFFFFu
#define DPF_DIFF (DPF_M_DIFF << DPF_V_DIFF)
/* Drive types */
/* These controllers support many different disk drive types:
type #sectors/ #surfaces/ #cylinders/
surface cylinder drive
7242 6 20 203 =24MB
7261 11 20 203 =45MB
7271 6 20 406 =48MB
3288 17 5 822 =67MB
7276 11 19 411 =86MB
7266 11 20 411 =90MB
3282 11 19 815 =170MB
3283 17 19 815 =263MB
On the T3281, each drive can be a different type. The size field
in each unit selects the drive capacity for each drive and thus
the drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE.
*/
#define DP_SZ(x) ((DPCY_##x) * (DPHD_##x) * (DPSC_##x) * DP_WDSC)
#define DP_ENT(x,y) (DP_##x), (DPCY_##x), (DPHD_##x), (DPSC_##x), (DP_C##y), (DPSZ_##x), (DPID_##x)
#define DP_7242 0
#define DPCY_7242 203
#define DPHD_7242 20
#define DPSC_7242 6
#define DPID_7242 0
#define DPSZ_7242 DP_SZ(7242)
#define DP_7261 1
#define DPCY_7261 203
#define DPHD_7261 20
#define DPSC_7261 11
#define DPID_7261 (5u << 5)
#define DPSZ_7261 DP_SZ(7261)
#define DP_7271 2
#define DPCY_7271 406
#define DPHD_7271 20
#define DPSC_7271 6
#define DPID_7271 0
#define DPSZ_7271 DP_SZ(7271)
#define DP_3288 3
#define DPCY_3288 822
#define DPHD_3288 5
#define DPSC_3288 17
#define DPID_3288 0
#define DPSZ_3288 DP_SZ(3288)
#define DP_7276 4
#define DPCY_7276 411
#define DPHD_7276 19
#define DPSC_7276 11
#define DPID_7276 (7 << 5)
#define DPSZ_7276 DP_SZ(7276)
#define DP_7266 5
#define DPCY_7266 411
#define DPHD_7266 20
#define DPSC_7266 11
#define DPID_7266 (6 << 5)
#define DPSZ_7266 DP_SZ(7276)
#define DP_3282 6
#define DPCY_3282 815
#define DPHD_3282 19
#define DPSC_3282 11
#define DPID_3282 0
#define DPSZ_3282 DP_SZ(3282)
#define DP_3283 7
#define DPCY_3283 815
#define DPHD_3283 19
#define DPSC_3283 17
#define DPID_3283 0
#define DPSZ_3283 DP_SZ(3283)
#define GET_PSC(x,s) ((int32) fmod (sim_gtime() / ((double) (x * DP_WDSC)), \
((double) (s))))
typedef struct {
uint32 dp_ctype; /* controller type */
uint32 dp_time; /* inter-word time */
uint32 dp_stime; /* inter-track time */
uint32 dp_flags; /* status flags */
uint32 dp_ski; /* seek interrupts */
uint32 dp_stopioe; /* stop on I/O error */
uint32 dp_test; /* test mode */
} DP_CTX;
typedef struct {
uint32 dtype; /* drive type */
uint32 cy; /* cylinders */
uint32 hd; /* heads */
uint32 sc; /* sectors */
uint32 ctype; /* controller */
uint32 capac; /* capacity */
uint32 id; /* ID */
} DP_TYPE;
typedef struct {
uint32 byte; /* offset in array */
uint32 mask; /* test mask */
uint32 fpos; /* from position */
uint32 tpos; /* to position */
} DP_SNSTAB;
static char *dp_cname[] = {
"7240", "7270", "7260", "7275", "7265", "T3281"
};
static uint32 dp_buf[DP_WDSC];
extern uint32 chan_ctl_time;
uint32 dpa_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 dpb_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 dp_disp (uint32 cidx, uint32 op, uint32 dva, uint32 *dvst);
uint32 dp_tio_status (uint32 cidx, uint32 un);
uint32 dp_tdv_status (uint32 cidx, uint32 un);
uint32 dp_aio_status (uint32 cidx, uint32 un);
void dp_set_sense (UNIT *uptr, uint32 *c);
t_stat dp_chan_err (uint32 dva, uint32 st);
t_stat dp_svc (UNIT *uptr);
t_stat dps_svc (UNIT *uptr);
t_stat dp_reset (DEVICE *dptr);
t_bool dp_inv_ad (UNIT *uptr, uint32 *da);
t_bool dp_inc_ad (UNIT *uptr);
t_stat dp_read (UNIT *uptr, uint32 da);
t_stat dp_write (UNIT *uptr, uint32 da);
t_stat dp_ioerr (UNIT *uptr);
t_bool dp_test_mode (uint32 cidx);
t_bool dp_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st);
int32 dp_clr_int (uint32 cidx);
void dp_set_ski (uint32 cidx, uint32 un);
void dp_clr_ski (uint32 cidx, uint32 un);
t_stat dp_attach (UNIT *uptr, CONST char *cptr);
t_stat dp_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat dp_set_auto (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat dp_set_ctl (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static DP_TYPE dp_tab[] = {
{ DP_ENT (7242, 7240) },
{ DP_ENT (7261, 7260) },
{ DP_ENT (7271, 7270) },
{ DP_ENT (3288, 3281) },
{ DP_ENT (7276, 7275) },
{ DP_ENT (7266, 7265) },
{ DP_ENT (3282, 3281) },
{ DP_ENT (3283, 3281) },
{ 0, 0, 0, 0, 0, 0 },
};
static DP_SNSTAB dp_sense_10B[] = {
{ 7, 0x00FF0000, 16, 0 },
{ 8, DPF_WCHK, DPF_V_WCHK, 6 },
{ 8, DPF_SNZ, DPF_V_SNZ, 2 },
{ 9, 0x01000000, 24, 0 },
{ 0, 0, 0, 0 }
};
static DP_SNSTAB dp_sense_16B[] = {
{ 8, DPF_WCHK, DPF_V_WCHK, 7 },
{ 8, DPF_EOC, DPF_V_EOC, 3},
{ 8, DPF_AIM, DPF_V_AIM, 2},
{ 14, 0xFF000000, 24, 0 },
{ 15, 0x00FF0000, 16, 0 },
{ 0, 0, 0, 0 }
};
/* Command table, indexed by command */
#define C_10B (1u << DP_C7240) | (1u << DP_C7270)
#define C_16B (1u << DP_C7260) | (1u << DP_C7275) | \
(1u << DP_C7265) | (1u << DP_C3281)
#define C_A (C_10B|C_16B) /* all */
#define C_F (1u << (DP_CTYPE)) /* fast */
#define C_C (1u << (DP_CTYPE + 1)) /* ctrl cmd */
static uint16 dp_cmd[256] = {
0, C_A, C_A, C_A, C_A|C_F, C_A, 0, C_16B|C_F,
0, C_A, C_A, 0, 0, 0, 0, C_16B|C_F|C_C,
0, 0, C_A, C_A|C_F, 0, 0, 0, C_16B|C_F,
0, 0, 0, 0, 0, 0, 0, C_16B|C_F|C_C,
0, 0, 0, C_10B|C_F, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, C_A, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, C_A, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, C_16B, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
/* DP data structures
dp_dev DP device descriptor
dp_unit DP unit descriptor
dp_reg DP register list
*/
dib_t dp_dib[] = {
{ DVA_DPA, &dpa_disp },
{ DVA_DPB, &dpb_disp }
};
DP_CTX dp_ctx[] = {
{ DP_C7270, 1, 20 },
{ DP_C7275, 1, 20 }
};
UNIT dpa_unit[] = {
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) },
{ UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) },
{ UDATA (&dp_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
};
UNIT dpb_unit[] = {
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) },
{ UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) },
{ UDATA (&dp_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
{ UDATA (&dps_svc, UNIT_DIS, 0) },
};
REG dpa_reg[] = {
{ HRDATA (CTYPE, dp_ctx[0].dp_ctype, 1), REG_HRO },
{ HRDATA (FLAGS, dp_ctx[0].dp_flags, 8) },
{ GRDATA (DIFF, dp_ctx[0].dp_flags, 16, 16, 16) },
{ HRDATA (SKI, dp_ctx[0].dp_ski, 16) },
{ HRDATA (TEST, dp_ctx[0].dp_test, 16) },
{ URDATA (ADDR, dpa_unit[0].UDA, 16, 32, 0, DP_NUMDR_16B, 0) },
{ URDATA (CMD, dpa_unit[0].UCMD, 16, 10, 0, DP_NUMDR_16B, 0) },
{ DRDATA (TIME, dp_ctx[0].dp_time, 24), PV_LEFT+REG_NZ },
{ DRDATA (STIME, dp_ctx[0].dp_stime, 24), PV_LEFT+REG_NZ },
{ FLDATA (STOP_IOE, dp_ctx[0].dp_stopioe, 0) },
{ HRDATA (DEVNO, dp_dib[0].dva, 12), REG_HRO },
{ NULL }
};
REG dpb_reg[] = {
{ HRDATA (CTYPE, dp_ctx[1].dp_ctype, 1), REG_HRO },
{ HRDATA (FLAGS, dp_ctx[1].dp_flags, 8) },
{ GRDATA (DIFF, dp_ctx[1].dp_flags, 16, 16, 16) },
{ HRDATA (SKI, dp_ctx[1].dp_ski, 16) },
{ HRDATA (TEST, dp_ctx[1].dp_test, 16) },
{ URDATA (ADDR, dpa_unit[1].UDA, 16, 32, 0, DP_NUMDR_16B, 0) },
{ URDATA (CMD, dpa_unit[1].UCMD, 16, 10, 0, DP_NUMDR_16B, 0) },
{ DRDATA (TIME, dp_ctx[1].dp_time, 24), PV_LEFT+REG_NZ },
{ DRDATA (STIME, dp_ctx[1].dp_stime, 24), PV_LEFT+REG_NZ },
{ FLDATA (STOP_IOE, dp_ctx[1].dp_stopioe, 0) },
{ HRDATA (DEVNO, dp_dib[1].dva, 12), REG_HRO },
{ NULL }
};
MTAB dp_mod[] = {
{ MTAB_XTD|MTAB_VDV, DP_C7240, NULL, "7240", &dp_set_ctl, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, DP_C7270, NULL, "7270", &dp_set_ctl, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, DP_C7260, NULL, "7260", &dp_set_ctl, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, DP_C7275, NULL, "7275", &dp_set_ctl, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, DP_C7265, NULL, "7265", &dp_set_ctl, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, DP_C3281, NULL, "T3281", &dp_set_ctl, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "controller", NULL, NULL, &dp_show_ctl },
{ UNIT_DTYPE, (DP_7242 << UNIT_V_DTYPE), "7242", NULL, NULL },
{ UNIT_DTYPE, (DP_7261 << UNIT_V_DTYPE), "7261", NULL, NULL },
{ UNIT_DTYPE, (DP_7271 << UNIT_V_DTYPE), "7271", NULL, NULL },
{ UNIT_DTYPE, (DP_7276 << UNIT_V_DTYPE), "7276", NULL, NULL },
{ UNIT_DTYPE, (DP_7266 << UNIT_V_DTYPE), "7266", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE) + UNIT_ATT,
"3288", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_3282 << UNIT_V_DTYPE) + UNIT_ATT,
"3282", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_3282 << UNIT_V_DTYPE) + UNIT_ATT,
"3282", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE),
"3288", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3282 << UNIT_V_DTYPE),
"3282", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3283 << UNIT_V_DTYPE),
"3283", NULL, NULL },
{ (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
{ UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", &dp_set_auto, NULL },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_3288 << UNIT_V_DTYPE),
NULL, "3288", &dp_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_3282 << UNIT_V_DTYPE),
NULL, "3282", &dp_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_3283 << UNIT_V_DTYPE),
NULL, "3283", &dp_set_size },
{ UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN",
&io_set_dvc, &io_show_dvc, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA",
&io_set_dva, &io_show_dva, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL,
NULL, &io_show_cst, NULL },
{ 0 }
};
DEVICE dp_dev[] = {
{
"DPA", dpa_unit, dpa_reg, dp_mod,
(2 * DP_NUMDR_16B) + 1, 16, 28, 1, 16, 32,
NULL, NULL, &dp_reset,
&io_boot, &dp_attach, NULL,
&dp_dib[0], DEV_DISABLE
},
{
"DPB", dpb_unit, dpb_reg, dp_mod,
(2 * DP_NUMDR_16B) + 1, 16, 28, 1, 16, 32,
NULL, NULL, &dp_reset,
&io_boot, &dp_attach, NULL,
&dp_dib[1], DEV_DISABLE
}
};
/* DP: IO dispatch routine */
uint32 dpa_disp (uint32 op, uint32 dva, uint32 *dvst)
{
return dp_disp (0, op, dva, dvst);
}
uint32 dpb_disp (uint32 op, uint32 dva, uint32 *dvst)
{
return dp_disp (1, op, dva, dvst);
}
uint32 dp_disp (uint32 cidx, uint32 op, uint32 dva, uint32 *dvst)
{
uint32 un = DVA_GETUNIT (dva);
UNIT *dp_unit = dp_dev[cidx].units;
UNIT *uptr;
int32 iu;
uint32 i;
DP_CTX *ctx;
if (cidx >= DP_NUMCTL) /* inv ctrl num? */
return DVT_NODEV;
ctx = &dp_ctx[cidx];
if (((un < DP_NUMDR) && /* un valid and */
((dp_unit[un].flags & UNIT_DIS) == 0)) || /* not disabled OR */
((un == 0xF) && (ctx->dp_ctype == DP_C3281))) /* 3281 unit F? */
uptr = dp_unit + un; /* un exists */
else return DVT_NODEV;
switch (op) { /* case on op */
case OP_SIO: /* start I/O */
*dvst = dp_tio_status (cidx, un); /* get status */
if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */
uptr->UCMD = DPS_INIT; /* start dev thread */
sim_activate (uptr, chan_ctl_time);
}
break;
case OP_TIO: /* test status */
*dvst = dp_tio_status (cidx, un); /* return status */
break;
case OP_TDV: /* test status */
*dvst = dp_tdv_status (cidx, un); /* return status */
break;
case OP_HIO: /* halt I/O */
*dvst = dp_tio_status (cidx, un); /* return status */
if (un != 0xF) { /* not controller */
if ((int32) un == chan_chk_chi (dva)) /* halt active ctlr int? */
chan_clr_chi (dva); /* clear ctlr int */
if (sim_is_active (uptr)) { /* chan active? */
sim_cancel (uptr); /* stop unit */
chan_uen (dva); /* uend */
}
dp_clr_ski (cidx, un); /* clear seek int */
sim_cancel (uptr + DP_SEEK); /* cancel seek compl */
}
else {
for (i = 0; i < DP_NUMDR; i++) { /* do every unit */
if (sim_is_active (&dp_unit[i])) { /* chan active? */
sim_cancel (&dp_unit[i]); /* cancel */
chan_uen (dva); /* uend */
}
dp_clr_ski (cidx, i); /* clear seek int */
sim_cancel (&dp_unit[i] + DP_SEEK); /* cancel seek compl */
}
chan_clr_chi (dva); /* clear chan int */
}
break;
case OP_AIO: /* acknowledge int */
iu = dp_clr_int (cidx); /* clear int */
*dvst = dp_aio_status (cidx, iu) | /* get status */
(iu << DVT_V_UN);
break;
default:
*dvst = 0;
return SCPE_IERR;
}
return 0;
}
/* Unit service */
t_stat dp_svc (UNIT *uptr)
{
uint32 i, da, wd, wd1, c[DPS_NBY_16B];
uint32 cidx = uptr->UCTX;
uint32 dva = dp_dib[cidx].dva;
uint32 dtype = GET_DTYPE (uptr->flags);
UNIT *dp_unit = dp_dev[cidx].units;
uint32 un = uptr - dp_unit;
DP_CTX *ctx = &dp_ctx[cidx];
int32 t, dc;
uint32 st, cmd, sc;
t_stat r;
if (uptr->UCMD == DPS_INIT) { /* init state? */
st = chan_get_cmd (dva, &cmd); /* get command */
if (CHS_IFERR (st)) /* channel error? */
return dp_chan_err (dva, st);
ctx->dp_flags = 0; /* clear status */
if (!(dp_cmd[cmd] & (1u << ctx->dp_ctype))) { /* cmd valid for dev? */
ctx->dp_flags |= DPF_PGE;
chan_uen (dva); /* uend */
return SCPE_OK;
}
if ((un == 0xF) && /* to controller? */
!(dp_cmd[cmd] & C_C)) { /* not valid? */
ctx->dp_flags |= DPF_PGE;
chan_uen (dva); /* uend */
return SCPE_OK;
}
uptr->UCMD = cmd; /* save state */
if (dp_cmd[cmd] & C_F) /* fast command? */
sim_activate_abs (uptr, chan_ctl_time); /* schedule soon */
else { /* data transfer */
sc = DPA_GETSC (uptr->UDA); /* new sector */
t = sc - GET_PSC (ctx->dp_time, dp_tab[dtype].sc); /* delta to new */
if (t < 0) /* wrap around? */
t = t + dp_tab[dtype].sc;
sim_activate_abs (uptr, t * ctx->dp_time * DP_WDSC); /* schedule op */
}
sim_cancel (uptr + DP_SEEK); /* cancel rest of seek */
return SCPE_OK;
}
else if (uptr->UCMD == DPS_END) { /* end state? */
st = chan_end (dva); /* set channel end */
if (CHS_IFERR (st)) /* channel error? */
return dp_chan_err (dva, st);
if (st == CHS_CCH) { /* command chain? */
uptr->UCMD = DPS_INIT; /* restart thread */
sim_activate (uptr, chan_ctl_time);
}
return SCPE_OK; /* done */
}
da = 0;
dc = 0;
switch (uptr->UCMD) {
case DPS_SEEK: /* seek */
case DPS_SEEKI:
for (i = 0; i < 4; i++)
c[i] = 0;
for (i = 0, st = 0; (i < 4) && (st != CHS_ZBC); i++) {
st = chan_RdMemB (dva, &c[i]); /* get byte */
if (CHS_IFERR (st)) /* channel error? */
return dp_chan_err (dva, st);
}
da = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
if (c[0] & 0xFC) /* hi 6b non-zero? */
ctx->dp_flags |= DPF_PGE; /* set prog err */
if (((i != 4) || (st != CHS_ZBC)) && /* length error? */
chan_set_chf (dva, CHF_LNTE)) { /* care? */
ctx->dp_flags |= DPF_PGE; /* set prog err */
return SCPE_OK;
}
if (i < 4) { /* at least 4? */
chan_uen (dva);
return SCPE_OK;
}
dc = DPA_GETCY (da); /* desired cyl */
case DPS_RECAL:
case DPS_RECALI:
t = abs (DPA_GETCY (uptr->UDA) - dc); /* get cyl diff */
ctx->dp_flags = (ctx->dp_flags & ~DPF_DIFF) |
((t & DPF_M_DIFF) << DPF_V_DIFF); /* save difference */
if (t == 0)
t = 1;
uptr->UDA = da; /* save addr */
sim_activate (uptr + DP_SEEK, t * ctx->dp_stime);
dp_unit[un + DP_SEEK].UCMD = /* sched seek */
(chan_tst_cmf (dva, CMF_CCH)? DSC_SEEK: uptr->UCMD & 0x80);
break; /* sched end */
case DPS_SENSE: /* sense */
for (i = 0; i < DPS_NBY_16B; i++)
c[i] = 0;
c[0] = (uptr->UDA >> 24) & 0xFF; /* 0-3 = disk addr */
c[1] = (uptr->UDA >> 16) & 0xFF;
c[2] = (uptr->UDA >> 8) & 0xFF;
c[3] = uptr->UDA & 0xFF;
c[4] = GET_PSC (ctx->dp_time, dp_tab[dtype].sc) | /* curr sector */
((sim_is_active (uptr) && ((uptr->UCMD & 0x7F) == DPS_SEEK))? 0x80: 0);
if (!DP_Q10B (ctx->dp_ctype)) { /* 16B only */
c[5] = un | dp_tab[dtype].id; /* unit # + id */
if (ctx->dp_ctype == DP_C3281) /* 3281 only */
c[7] = un; /* unique id */
c[10] = (ctx->dp_ski >> 8) & 0xFF; /* seek intr */
c[11] = ctx->dp_ski & 0xFF;
}
dp_set_sense (uptr, &c[0]); /* other bytes */
for (i = 0, st = 0; (i < DPS_NBY) && (st != CHS_ZBC); i++) {
st = chan_WrMemB (dva, c[i]); /* store char */
if (CHS_IFERR (st)) /* channel error? */
return dp_chan_err (dva, st);
}
if ((i != DPS_NBY) || (st != CHS_ZBC)) { /* length error? */
ctx->dp_flags |= DPF_PGE; /* set prog err */
if (chan_set_chf (dva, CHF_LNTE)) /* do we care? */
return SCPE_OK;
}
break;
case DPS_WRITE: /* write */
if (uptr->flags & UNIT_RO) { /* write locked? */
ctx->dp_flags |= DPF_WPE;
chan_uen (dva); /* uend */
return SCPE_OK;
}
if (dp_inv_ad (uptr, &da)) { /* invalid addr? */
chan_uen (dva); /* uend */
return SCPE_OK;
}
for (i = 0, st = 0; i < DP_WDSC; i++) { /* sector loop */
if (st != CHS_ZBC) { /* chan not done? */
st = chan_RdMemW (dva, &wd); /* read word */
if (CHS_IFERR (st)) { /* channel error? */
dp_inc_ad (uptr); /* da increments */
return dp_chan_err (dva, st);
}
}
else wd = 0;
dp_buf[i] = wd; /* store in buffer */
}
if ((r = dp_write (uptr, da))) /* write buf, err? */
return r;
if (dp_end_sec (uptr, DP_WDSC, DP_WDSC, st)) /* transfer done? */
return SCPE_OK; /* err or cont */
break;
/* Write header "writes" eight bytes per sector and throws them in the bit bucket */
case DPS_WHDR:
if (uptr->flags & UNIT_RO) { /* write locked? */
ctx->dp_flags |= DPF_WPE;
chan_uen (dva); /* uend */
return SCPE_OK;
}
if (dp_inv_ad (uptr, &da)) { /* invalid addr? */
chan_uen (dva); /* uend */
return SCPE_OK;
}
if (DPA_GETSC (uptr->UDA) != 0) { /* must start at sec 0 */
ctx->dp_flags |= DPF_SNZ;
chan_uen (dva);
return SCPE_OK;
}
for (i = 0, st = 0; (i < 8) && (st != CHS_ZBC); i++) { /* sector loop */
if (st != CHS_ZBC) { /* chan not done? */
st = chan_RdMemB (dva, &wd); /* read word */
if (CHS_IFERR (st)) { /* channel error? */
dp_inc_ad (uptr); /* da increments */
return dp_chan_err (dva, st);
}
}
}
if (dp_end_sec (uptr, i, 8, st)) /* transfer done? */
return SCPE_OK; /* err or cont */
/* Write check must be done by bytes to get precise miscompare */
case DPS_CHECK: /* write check */
if (dp_inv_ad (uptr, &da)) { /* invalid addr? */
chan_uen (dva); /* uend */
return SCPE_OK;
}
if ((r = dp_read (uptr, da))) /* read buf, error? */
return r;
for (i = 0, st = 0; (i < (DP_WDSC * 4)) && (st != CHS_ZBC); i++) {
st = chan_RdMemB (dva, &wd); /* read byte */
if (CHS_IFERR (st)) { /* channel error? */
dp_inc_ad (uptr); /* da increments */
return dp_chan_err (dva, st);
}
wd1 = (dp_buf[i >> 2] >> (24 - ((i & 0x3) * 8))) & 0xFF; /* byte */
if (wd != wd1) { /* check error? */
dp_inc_ad (uptr); /* da increments */
ctx->dp_flags |= DPF_WCHK; /* set status */
chan_uen (dva); /* force uend */
return SCPE_OK;
}
}
if (dp_end_sec (uptr, i, DP_WDSC * 4, st)) /* transfer done? */
return SCPE_OK; /* err or cont */
break;
case DPS_READ: /* read */
if (dp_inv_ad (uptr, &da)) { /* invalid addr? */
chan_uen (dva); /* uend */
return SCPE_OK;
}
if ((r = dp_read (uptr, da))) /* read buf, error? */
return r;
for (i = 0, st = 0; (i < DP_WDSC) && (st != CHS_ZBC); i++) {
st = chan_WrMemW (dva, dp_buf[i]); /* store in mem */
if (CHS_IFERR (st)) { /* channel error? */
dp_inc_ad (uptr); /* da increments */
return dp_chan_err (dva, st);
}
}
if (dp_end_sec (uptr, i, DP_WDSC, st)) /* transfer done? */
return SCPE_OK; /* err or cont */
break;
/* Read header reads 8 bytes per sector */
case DPS_RHDR: /* read header */
if (dp_inv_ad (uptr, &da)) { /* invalid addr? */
chan_uen (dva); /* uend */
return SCPE_OK;
}
c[0] = c[5] = c[6] = c[7] = 0;
wd = DPA_GETCY (uptr->UDA);
c[1] = (wd >> 8) & 0xFF;
c[2] = wd & 0xFF;
c[3] = DPA_GETHD (uptr->UDA);
c[4] = DPA_GETSC (uptr->UDA);
for (i = 0, st = 0; (i < 8) && (st != CHS_ZBC); i++) {
st = chan_WrMemB (dva, c[i]); /* store in mem */
if (CHS_IFERR (st)) { /* channel error? */
dp_inc_ad (uptr); /* da increments */
return dp_chan_err (dva, st);
}
}
if (dp_end_sec (uptr, i, 8, st)) /* transfer done? */
return SCPE_OK; /* err or cont */
break;
/* Test mode is not really implemented */
case DPS_TEST: /* test mode */
if (!dp_test_mode (cidx)) /* enter test mode */
return SCPE_OK;
break;
case DPS_RSRV: /* reserve */
case DPS_RLS: /* release */
case DPS_RLSA: /* release */
break; /* nop */
}
uptr->UCMD = DPS_END; /* op done, next state */
sim_activate (uptr, chan_ctl_time);
return SCPE_OK;
}
/* Seek completion service */
t_stat dps_svc (UNIT *uptr)
{
uint32 cidx = uptr->UCTX;
DP_CTX *ctx = &dp_ctx[cidx];
UNIT *dp_unit = dp_dev[cidx].units;
uint32 un = uptr - dp_unit - DP_SEEK;
uint32 dtype = GET_DTYPE (dp_unit[un].flags);
if (uptr->UCMD != DSC_SEEK) { /* int? */
if (chan_chk_chi (dp_dib[cidx].dva) >= 0) { /* ctl int pending? */
sim_activate (uptr, ctx->dp_time * dp_tab[dtype].sc);
uptr->UCMD = DSC_SEEKW;
}
else dp_set_ski (cidx, un);
}
return SCPE_OK;
}
/* Common read/write sector end routine
case 1 - more to transfer, not end cylinder - reschedule, return TRUE
case 2 - more to transfer, end cylinder - uend, return TRUE
case 3 - transfer done, length error - uend, return TRUE
case 4 - transfer done, no length error - return FALSE (sched end state)
*/
t_bool dp_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st)
{
uint32 cidx = uptr->UCTX;
uint32 dva = dp_dib[cidx].dva;
uint32 dtype = GET_DTYPE (uptr->flags);
DP_CTX *ctx = &dp_ctx[cidx];
if (st != CHS_ZBC) { /* end record? */
if (dp_inc_ad (uptr)) { /* inc addr, cross cyl? */
ctx->dp_flags |= (DPF_IVA | DPF_EOC);
chan_uen (dva); /* uend */
}
else sim_activate (uptr, ctx->dp_time * 16); /* no, next sector */
return TRUE;
}
dp_inc_ad (uptr); /* just incr addr */
if (lnt != exp) { /* length error at end? */
if (exp == 8) /* hdr op? */
ctx->dp_flags |= DPF_PGE; /* set PGE */
if (chan_set_chf (dva, CHF_LNTE)) /* do we care? */
return TRUE;
}
return FALSE; /* cmd done */
}
/* DP status routines */
/* The ctrl is busy if any drive is busy.
The device is busy if either the main unit or the seek unit is busy */
uint32 dp_tio_status (uint32 cidx, uint32 un)
{
uint32 i;
DP_CTX *ctx = &dp_ctx[cidx];
UNIT *dp_unit = dp_dev[cidx].units;
uint32 stat = DVS_AUTO;
for (i = 0; i < DP_NUMDR; i++) {
if (sim_is_active (&dp_unit[i])) {
stat |= (DVS_CBUSY|(CC2 << DVT_V_CC));
break;
}
}
if (sim_is_active (&dp_unit[un]) ||
sim_is_active (&dp_unit[un + DP_SEEK]))
stat |= (DVS_DBUSY|(CC2 << DVT_V_CC));
return DVS_AUTO;
}
uint32 dp_tdv_status (uint32 cidx, uint32 un)
{
uint32 st;
DP_CTX *ctx = &dp_ctx[cidx];
UNIT *dp_unit = dp_dev[cidx].units;
t_bool on_cyl;
st = 0;
on_cyl = !sim_is_active (&dp_unit[un + DP_SEEK]) ||
(dp_unit[un + DP_SEEK].UCMD == DSC_SEEKW);
if (DP_Q10B (dp_ctx[cidx].dp_ctype))
st = ((dp_ctx[cidx].dp_flags & DPF_IVA)? 0x20: 0) |
(on_cyl? 0x04: 0);
else st = ((dp_ctx[cidx].dp_flags & DPF_PGE)? 0x20: 0) |
((dp_ctx[cidx].dp_flags & DPF_WPE)? 0x08: 0);
return st;
}
uint32 dp_aio_status (uint32 cidx, uint32 un)
{
uint32 st;
DP_CTX *ctx = &dp_ctx[cidx];
UNIT *dp_unit = dp_dev[cidx].units;
t_bool on_cyl;
st = 0;
on_cyl = !sim_is_active (&dp_unit[un + DP_SEEK]) ||
(dp_unit[un + DP_SEEK].UCMD == DSC_SEEKW);
if ((DP_Q10B (dp_ctx[cidx].dp_ctype)) && on_cyl)
st |= 0x04;
if (chan_chk_chi (dp_dib[cidx].dva) < 0)
st |= 0x08;
return st;
}
/* Set sense status */
void dp_set_sense (UNIT *uptr, uint32 *c)
{
uint32 cidx = uptr->UCTX;
UNIT *sptr = uptr + DP_SEEK;
DP_CTX *ctx = &dp_ctx[cidx];
uint8 data;
DP_SNSTAB *tptr;
if (sim_is_active (sptr) &&
(sptr->UCMD != DSC_SEEKW))
ctx->dp_flags |= DPF_AIM;
else ctx->dp_flags &= ~DPF_AIM;
if (DP_Q10B (ctx->dp_ctype))
tptr = dp_sense_10B;
else tptr = dp_sense_16B;
while (tptr->byte != 0) {
if (ctx->dp_flags & tptr->mask) {
data = (uint8) ((ctx->dp_flags & tptr->mask) >> tptr->fpos);
c[tptr->byte] |= (data << tptr->tpos);
}
}
return;
}
/* Validate disk address */
t_bool dp_inv_ad (UNIT *uptr, uint32 *da)
{
uint32 dtype = GET_DTYPE (uptr->flags);
uint32 cy = DPA_GETCY (uptr->UDA);
uint32 hd = DPA_GETHD (uptr->UDA);
uint32 sc = DPA_GETSC (uptr->UDA);
if ((cy >= dp_tab[dtype].cy) ||
(hd >= dp_tab[dtype].hd) ||
(sc >= dp_tab[dtype].sc))
return TRUE;
if (da) /* return word addr */
*da = ((((cy * dp_tab[dtype].hd) + hd) * dp_tab[dtype].sc) + sc) * DP_WDSC;
return FALSE;
}
/* Increment disk address */
t_bool dp_inc_ad (UNIT *uptr)
{
uint32 dtype = GET_DTYPE (uptr->flags);
uint32 cy = DPA_GETCY (uptr->UDA);
uint32 hd = DPA_GETHD (uptr->UDA);
uint32 sc = DPA_GETSC (uptr->UDA);
sc = sc + 1; /* sector++ */
if (sc >= dp_tab[dtype].sc) { /* overflow? */
sc = 0; /* wrap sector */
hd = hd + 1; /* head++ */
if (hd >= dp_tab[dtype].hd) /* overflow? */
hd = 0; /* wrap heads */
}
uptr->UDA = (cy << DPA_V_CY) | (hd << DPA_V_HD) | (sc << DPA_V_SC);
if ((hd == 0) && (sc == 0))
return TRUE;
return FALSE;
}
/* Read and write sector */
t_stat dp_read (UNIT *uptr, uint32 da)
{
int32 err, awc;
err = fseek (uptr->fileref, da * sizeof (int32), SEEK_SET);
if (err == 0) {
awc = fxread (dp_buf, sizeof (uint32), DP_WDSC, uptr->fileref);
err = ferror (uptr->fileref);
for (; awc < DP_WDSC; awc++) /* fill buf */
dp_buf[awc] = 0;
}
if (err != 0)
return dp_ioerr (uptr);
return SCPE_OK;
}
t_stat dp_write (UNIT *uptr, uint32 da)
{
int32 err;
err = fseek (uptr->fileref, da * sizeof (int32), SEEK_SET);
if (err == 0) {
fxwrite (dp_buf, sizeof (uint32), DP_WDSC, uptr->fileref);
err = ferror (uptr->fileref);
}
if (err != 0)
return dp_ioerr (uptr);
return SCPE_OK;
}
t_stat dp_ioerr (UNIT *uptr)
{
uint32 cidx = uptr->UCTX;
uint32 dva = dp_dib[cidx].dva;
sim_perror ("DP I/O error");
clearerr (uptr->fileref);
dp_ctx[cidx].dp_flags |= DPF_DPE; /* set DPE flag */
chan_set_chf (dva, CHF_XMDE);
chan_uen (dva); /* force uend */
return SCPE_IOERR;
}
/* Test mode */
t_bool dp_test_mode (uint32 cidx)
{
DP_CTX *ctx = &dp_ctx[cidx];
uint32 dva = dp_dib[cidx].dva;
uint32 i, st, wd;
ctx->dp_test = 0;
for (i = 0, st = 0; i < DPT_NBY; i++) { /* sector loop */
if (st != CHS_ZBC) { /* chan not done? */
st = chan_RdMemB (dva, &wd); /* read word */
if (CHS_IFERR (st)) {
dp_chan_err (dva, st);
return FALSE;
}
}
else wd = 0;
ctx->dp_test |= (wd & 0xFF) << (i * 8);
}
return TRUE;
}
/* Channel error */
t_stat dp_chan_err (uint32 dva, uint32 st)
{
chan_uen (dva); /* uend */
if (st < CHS_ERR)
return st;
return SCPE_OK;
}
/* Clear controller/device interrupt */
int32 dp_clr_int (uint32 cidx)
{
int32 iu;
DP_CTX *ctx = &dp_ctx[cidx];
if ((iu = chan_clr_chi (dp_dib[cidx].dva)) >= 0) { /* chan int? clear */
if (ctx->dp_ski != 0) /* more int? */
chan_set_dvi (dp_dib[cidx].dva); /* set INP */
return iu;
}
for (iu = 0; iu < (int32) DP_NUMDR; iu++) { /* seek int? */
if (ctx->dp_ski & (1u << iu)) {
dp_clr_ski (cidx, iu); /* clear */
return iu;
}
}
return 0;
}
/* Set seek interrupt */
void dp_set_ski (uint32 cidx, uint32 un)
{
dp_ctx[cidx].dp_ski |= (1u << un);
chan_set_dvi (dp_dib[cidx].dva); /* set INP */
return;
}
/* Clear seek interrupt */
void dp_clr_ski (uint32 cidx, uint32 un)
{
dp_ctx[cidx].dp_ski &= ~(1u << un); /* clear */
if (dp_ctx[cidx].dp_ski != 0) /* more int? */
chan_set_dvi (dp_dib[cidx].dva); /* set INP */
else if (chan_chk_chi (dp_dib[cidx].dva) < 0) /* any int? */
chan_clr_chi (dp_dib[cidx].dva); /* clr INP */
return;
}
/* Reset routine */
t_stat dp_reset (DEVICE *dptr)
{
uint32 i;
uint32 cidx = dptr - dp_dev;
UNIT *dp_unit;
DP_CTX *ctx;
if (cidx >= DP_NUMCTL)
return SCPE_IERR;
dp_unit = dptr->units;
ctx = &dp_ctx[cidx];
for (i = 0; i < DP_NUMDR_16B; i++) {
sim_cancel (&dp_unit[i]); /* stop dev thread */
sim_cancel (&dp_unit[i + DP_SEEK]); /* stop seek thread */
dp_unit[i].UDA = 0;
dp_unit[i].UCMD = 0;
dp_unit[i].UCTX = cidx;
}
ctx->dp_flags = 0;
ctx->dp_ski = 0;
ctx->dp_test = 0;
chan_reset_dev (dp_dib[cidx].dva); /* clr int, active */
return SCPE_OK;
}
/* Device attach */
t_stat dp_attach (UNIT *uptr, CONST char *cptr)
{
uint32 i, p;
t_stat r;
uptr->capac = dp_tab[GET_DTYPE (uptr->flags)].capac;
r = attach_unit (uptr, cptr); /* attach unit */
if (r != SCPE_OK) /* error? */
return r;
if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */
return SCPE_OK;
p = sim_fsize (uptr->fileref);
if (p == 0) /* new file? */
return SCPE_OK;
for (i = 0; dp_tab[i].sc != 0; i++) {
if ((dp_tab[i].ctype == DP_C3281) && /* only on 3281 */
(p <= (dp_tab[i].capac * (uint32) sizeof (int32)))) {
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
uptr->capac = dp_tab[i].capac;
return SCPE_OK;
}
}
return SCPE_OK;
}
/* Set drive type command validation routine */
t_stat dp_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
uint32 dtype = GET_DTYPE (val);
uint32 cidx = uptr->UCTX;
if (cidx >= DP_NUMCTL) /* valid ctrl idx? */
return SCPE_IERR;
if (uptr->flags & UNIT_ATT) /* unattached? */
return SCPE_ALATT;
if (dp_ctx[cidx].dp_ctype != DP_C3281) /* only on 3281 */
return SCPE_NOFNC;
uptr->capac = dp_tab[dtype].capac;
return SCPE_OK;
}
/* Set unit autosize validation routine */
t_stat dp_set_auto (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
uint32 cidx = uptr->UCTX;
if (cidx >= DP_NUMCTL) /* valid ctrl idx? */
return SCPE_IERR;
if (uptr->flags & UNIT_ATT) /* unattached? */
return SCPE_ALATT;
if (dp_ctx[cidx].dp_ctype != DP_C3281) /* only on 3281 */
return SCPE_NOFNC;
return SCPE_OK;
}
/* Set controller type command validation routine */
t_stat dp_set_ctl (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
uint32 i, new_dtyp, cidx = uptr->UCTX;
DP_CTX *ctx = &dp_ctx[cidx];
UNIT *dp_unit = dp_dev[cidx].units;
if ((cidx >= DP_NUMCTL) || (val >= DP_CTYPE)) /* valid ctrl idx? */
return SCPE_IERR;
if (val == dp_ctx[cidx].dp_ctype) /* no change? */
return SCPE_OK;
for (i = 0; i < DP_NUMDR; i++) { /* all units detached? */
if ((dp_unit[i].flags & UNIT_ATT) != 0)
return SCPE_ALATT;
}
for (i = new_dtyp = 0; dp_tab[i].sc != 0; i++) { /* find default capac */
if (dp_tab[i].ctype == val) {
new_dtyp = i;
break;
}
}
if (dp_tab[new_dtyp].sc == 0)
return SCPE_IERR;
ctx->dp_ctype = val; /* new ctrl type */
for (i = 0; i < DP_NUMDR_16B; i++) {
if (i >= DP_NUMDR)
dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DISABLE) | UNIT_DIS;
else dp_unit[i].flags = (dp_unit[i].flags | UNIT_DISABLE) & ~UNIT_DIS;
if (val != DP_C3281)
dp_unit[i].flags &= ~UNIT_AUTO;
dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DTYPE) |
(new_dtyp << UNIT_V_DTYPE);
dp_unit[i].capac = dp_tab[new_dtyp].capac;
}
return SCPE_OK;
}
t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
uint32 cidx = uptr->UCTX;
if (cidx >= DP_NUMCTL) /* valid ctrl idx? */
return SCPE_IERR;
if (dp_ctx[cidx].dp_ctype >= DP_CTYPE)
return SCPE_IERR;
fprintf (st, "%s controller", dp_cname[dp_ctx[cidx].dp_ctype]);
return SCPE_OK;
}