blob: 0990ed72b119a8ae31976f0da2359ffd1c425605 [file] [log] [blame] [raw]
/* sigma_dp.c: 7270/T3281 disk pack controller
Copyright (c) 2008, 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 7270/T3281 disk pack controller
Transfers are always done a sector at a time.
*/
#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 0x7
#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_C7270 0 /* 7270 ctrl */
#define DP_C3281 1 /* 3281 ctrl */
#define DP_NUMDR_7270 8 /* drives/ctrl */
#define DP_NUMDR_3281 15
#define DP_CONT DP_NUMDR_3281 /* ctrl's drive # */
#define DP_WDSC 256 /* words/sector */
#define DP_BYHD 8 /* byte/header */
#define DP_NUMDR ((uint32) ((ctx->dp_ctype == DP_C7270)? DP_NUMDR_7270: DP_NUMDR_3281))
#define DP_SEEK (DP_CONT + 1)
/* 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_7270 10
#define DPS_NBY_3281 16
#define DPS_NBY ((uint32) ((ctx->dp_ctype == DP_C7270)? DPS_NBY_7270: DPS_NBY_3281))
/* Test mode */
#define DPT_NBY_7270 1 /* bytes/test mode spec */
#define DPT_NBY_3281 2
#define DPT_NBY ((uint32) ((ctx->dp_ctype == DP_C7270)? DPT_NBY_7270: DPT_NBY_3281))
/* 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 */
#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 204
7261 11 20 204
7271 6 20 408
3288 17 5 823 =67MB
7275 11 19 411 =88MB
7276 11 19 815 =176MB
3283 17 18 815
In theory, 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)
#define DP_7242 0
#define DPCY_7242 204
#define DPHD_7242 20
#define DPSC_7242 6
#define DPSZ_7242 DP_SZ(7242)
#define DP_7261 1
#define DPCY_7261 204
#define DPHD_7261 20
#define DPSC_7261 11
#define DPSZ_7261 DP_SZ(7261)
#define DP_7271 2
#define DPCY_7271 408
#define DPHD_7271 20
#define DPSC_7271 6
#define DPSZ_7271 DP_SZ(7271)
#define DP_3288 3
#define DPCY_3288 822
#define DPHD_3288 5
#define DPSC_3288 17
#define DPSZ_3288 DP_SZ(3288)
#define DP_7275 4
#define DPCY_7275 411
#define DPHD_7275 19
#define DPSC_7275 11
#define DPSZ_7275 DP_SZ(7275)
#define DP_7276 5
#define DPCY_7276 815
#define DPHD_7276 19
#define DPSC_7276 11
#define DPSZ_7276 DP_SZ(7276)
#define DP_3283 6
#define DPCY_3283 815
#define DPHD_3283 19
#define DPSC_3283 17
#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_flags; /* status flags */
uint32 dp_ski; /* seek interrupts */
uint32 dp_time; /* inter-word time */
uint32 dp_stime; /* inter-track time */
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 */
} DP_TYPE;
typedef struct {
uint32 byte; /* offset in array */
uint32 mask; /* test mask */
uint32 fpos; /* from position */
uint32 tpos; /* to position */
} DP_SNSTAB;
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, char *cptr);
t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dp_set_ctl (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, void *desc);
static DP_TYPE dp_tab[] = {
{ DP_ENT (7242, 7270) },
{ DP_ENT (7261, 3281) },
{ DP_ENT (7271, 7270) },
{ DP_ENT (3288, 3281) },
{ DP_ENT (7275, 3281) },
{ DP_ENT (7276, 3281) },
{ DP_ENT (3283, 3281) },
{ 0, 0, 0, 0, 0, 0 },
};
static DP_SNSTAB dp_sense_7270[] = {
{ 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_3281[] = {
{ 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_7270 (1u << DP_C7270)
#define C_3281 (1u << DP_C3281)
#define C_B (C_7270|C_3281)
#define C_F (1u << 2) /* fast */
#define C_C (1u << 3) /* ctrl cmd */
static uint8 dp_cmd[256] = {
0, C_B, C_B, C_B, C_B|C_F, C_B, 0, C_3281|C_F,
0, C_B, C_B, 0, 0, 0, 0, C_3281|C_F|C_C,
0, 0, C_B, C_B|C_F, 0, 0, 0, C_3281|C_F,
0, 0, 0, 0, 0, 0, 0, C_3281|C_F|C_C,
0, 0, 0, C_7270|C_F, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, C_B, 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_B, 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_3281, 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 },
{ DP_C3281 }
};
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_3281, 0) },
{ URDATA (CMD, dpa_unit[0].UCMD, 16, 10, 0, DP_NUMDR_3281, 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_3281, 0) },
{ URDATA (CMD, dpa_unit[1].UCMD, 16, 10, 0, DP_NUMDR_3281, 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_C7270, "C7270", "C7270",
&dp_set_ctl, &dp_show_ctl, NULL },
{ MTAB_XTD|MTAB_VDV, DP_C3281, "C3281", "C3281",
&dp_set_ctl, &dp_show_ctl, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_7242 << UNIT_V_DTYPE) + UNIT_ATT,
"7242", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_7261 << UNIT_V_DTYPE) + UNIT_ATT,
"7261", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_7271 << UNIT_V_DTYPE) + UNIT_ATT,
"7271", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE) + UNIT_ATT,
"3288", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_7275 << UNIT_V_DTYPE) + UNIT_ATT,
"7275", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_7276 << UNIT_V_DTYPE) + UNIT_ATT,
"7276", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (DP_3283 << UNIT_V_DTYPE) + UNIT_ATT,
"3283", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7242 << UNIT_V_DTYPE),
"7242", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7261 << UNIT_V_DTYPE),
"7261", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7271 << UNIT_V_DTYPE),
"7271", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE),
"3288", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7275 << UNIT_V_DTYPE),
"7275", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7276 << UNIT_V_DTYPE),
"7276", 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", NULL },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_7242 << UNIT_V_DTYPE),
NULL, "7242", &dp_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_7261 << UNIT_V_DTYPE),
NULL, "7261", &dp_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_7271 << UNIT_V_DTYPE),
NULL, "7271", &dp_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_3288 << UNIT_V_DTYPE),
NULL, "3288", &dp_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_7275 << UNIT_V_DTYPE),
NULL, "7275", &dp_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_7276 << UNIT_V_DTYPE),
NULL, "7276", &dp_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (DP_7276 << 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_3281) + 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_3281) + 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 = dp_unit + un;
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) || /* inv unit num? */
((uptr->flags & UNIT_DIS) && /* disabled unit? */
((un != 0xF) || (ctx->dp_ctype != C_3281)))) /* not 3281 unit F? */
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_3281];
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 = 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;
else t = abs (t);
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_3281; i++)
c[i] = 0;
c[0] = (uptr->UDA >> 24) & 0xFF;
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 (ctx->dp_ctype == DP_C3281) {
c[5] = c[7] = un;
c[10] = (ctx->dp_ski >> 8) & 0xFF;
c[11] = ctx->dp_ski & 0xFF;
}
dp_set_sense (uptr, &c[0]);
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) {
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 % 4) * 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 routine */
uint32 dp_tio_status (uint32 cidx, uint32 un)
{
uint32 i;
DP_CTX *ctx = &dp_ctx[cidx];
UNIT *dp_unit = dp_dev[cidx].units;
for (i = 0; i < DP_NUMDR; i++) {
if (sim_is_active (&dp_unit[i]))
return (DVS_AUTO|DVS_CBUSY|DVS_DBUSY|(CC2 << DVT_V_CC));
}
for (i = 0; i < DP_NUMDR; i++) {
if (sim_is_active (&dp_unit[i + DP_SEEK]) &&
(dp_unit[i + DP_SEEK].UCMD != DSC_SEEKW))
return (DVS_AUTO|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_ctx[cidx].dp_ctype == DP_C7270)
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_ctx[cidx].dp_ctype == DP_C7270) && 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 (ctx->dp_ctype == DP_C7270)
tptr = dp_sense_7270;
else tptr = dp_sense_3281;
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; i++) {
sim_cancel (&dp_unit[i]); /* stop dev 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, 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);
for (i = 0; dp_tab[i].sc != 0; i++) {
if (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, 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_tab[dtype].ctype != dp_ctx[cidx].dp_ctype) /* valid for curr ctrl? */
return SCPE_NOFNC;
uptr->capac = dp_tab[dtype].capac;
return SCPE_OK;
}
/* Set controller type command validation routine */
t_stat dp_set_ctl (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 i, cidx = uptr->UCTX;
DP_CTX *ctx = &dp_ctx[cidx];
UNIT *dp_unit = dp_dev[cidx].units;
if ((cidx >= DP_NUMCTL) || (val >= DP_NUMCTL)) /* valid ctrl idx? */
return SCPE_IERR;
if (val == dp_ctx[cidx].dp_ctype)
return SCPE_OK;
for (i = 0; i < DP_NUMDR; i++) { /* all units detached? */
if (dp_unit[i].flags & UNIT_ATT)
return SCPE_ALATT;
}
for (i = 0; i < DP_NUMDR; i++) {
if (val == DP_C7270) { /* changing to 7270? */
dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DTYPE) |
(DP_7271 << UNIT_V_DTYPE);
dp_unit[i].capac = DPSZ_7271;
if (i >= DP_NUMDR_7270)
dp_unit[i].flags = (dp_unit[i].flags | UNIT_DIS) & ~UNIT_DISABLE;
}
else {
dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DTYPE) |
(DP_7275 << UNIT_V_DTYPE);
dp_unit[i].capac = DPSZ_7275;
if (i >= DP_NUMDR_7270)
dp_unit[i].flags = dp_unit[i].flags | UNIT_DISABLE;
}
}
return SCPE_OK;
}
t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, void *desc)
{
uint32 cidx = uptr->UCTX;
if (cidx >= DP_NUMCTL) /* valid ctrl idx? */
return SCPE_IERR;
if (dp_ctx[cidx].dp_ctype == DP_C7270)
fprintf (st, "7270 controller");
else fprintf (st, "3281 controller");
return SCPE_OK;
}