1 /* TAPECCWS.C (c) Copyright Roger Bowler, 1999-2009 */
2 /* Hercules Tape Device Handler CCW Processing */
3
4 /* Original Author: Roger Bowler */
5 /* Prime Maintainer: Ivan Warren */
6 /* Secondary Maintainer: "Fish" (David B. Trout) */
7
8 /*-------------------------------------------------------------------*/
9 /* This module contains the CCW handling functions for tape devices. */
10 /* */
11 /* The subroutines in this module are called by the general tape */
12 /* device handler (tapedev.c) when the tape format is AWSTAPE. */
13 /* */
14 /* Messages issued by this module are prefixed HHCTA0nn */
15 /*-------------------------------------------------------------------*/
16
17 /*-------------------------------------------------------------------*/
18 /* Reference information: */
19 /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide */
20 /* GA32-0331 IBM 3590 Hardware Reference */
21 /* GA32-0329 IBM 3590 Introduction and Planning Guide */
22 /* SG24-2594 IBM 3590 Multiplatform Implementation */
23 /* ANSI INCITS 131-1994 (R1999) SCSI-2 Reference */
24 /* GA32-0127 IBM 3490E Hardware Reference */
25 /* GC35-0152 EREP Release 3.5.0 Reference */
26 /* SA22-7204 ESA/390 Common I/O-Device Commands */
27 /*-------------------------------------------------------------------*/
28
29 #include "hstdinc.h"
30 #include "hercules.h" /* need Hercules control blocks */
31 #include "tapedev.h" /* Main tape handler header file */
32
33 //#define ENABLE_TRACING_STMTS // (Fish: DEBUGGING)
34
35 #ifdef ENABLE_TRACING_STMTS
36 #if !defined(DEBUG)
37 #warning DEBUG required for ENABLE_TRACING_STMTS
38 #endif
39 // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h)
40 #else
41 #undef TRACE
42 #undef ASSERT
43 #undef VERIFY
44 #define TRACE 1 ? ((void)0) : logmsg
45 #define ASSERT(a)
46 #define VERIFY(a) ((void)(a))
47 #endif
48
49 /*-------------------------------------------------------------------*/
50 /* (forward declarations needed by below tables) */
51 /*-------------------------------------------------------------------*/
52
53 extern BYTE TapeCommands3410 [];
54 extern BYTE TapeCommands3420 [];
55 extern BYTE TapeCommands3422 [];
56 extern BYTE TapeCommands3430 [];
57 extern BYTE TapeCommands3480 [];
58 extern BYTE TapeCommands3490 [];
59 extern BYTE TapeCommands3590 [];
60 extern BYTE TapeCommands9347 [];
61
62 extern TapeSenseFunc build_sense_3410;
63 extern TapeSenseFunc build_sense_3420;
64 #define build_sense_3422 build_sense_3420
65 #define build_sense_3430 build_sense_3420
66 extern TapeSenseFunc build_sense_3480_etal;
67 extern TapeSenseFunc build_sense_3490;
68 extern TapeSenseFunc build_sense_3590;
69 extern TapeSenseFunc build_sense_Streaming;
70
71 /*-------------------------------------------------------------------*/
72 /* TapeDevtypeList */
73 /* Format: */
74 /* */
75 /* A: Supported Device Type, */
76 /* B: Command table index, (TapeCommandTable) */
77 /* C: UC on RewUnld, (1/0 = true/false) */
78 /* D: CUE on RewUnld, (1/0 = true/false) */
79 /* E: Sense Build Function table index (TapeSenseTable) */
80 /* */
81 /*-------------------------------------------------------------------*/
82
83 int TapeDevtypeList [] =
84 {
85 /* A B C D E */
86 0x3410, 0, 1, 0, 0,
87 0x3411, 0, 1, 0, 0,
88 0x3420, 1, 1, 1, 1,
89 0x3422, 2, 0, 0, 2,
90 0x3430, 3, 0, 0, 3,
91 0x3480, 4, 0, 0, 4,
92 0x3490, 5, 0, 0, 5,
93 0x3590, 6, 0, 0, 6,
94 0x9347, 7, 0, 0, 7,
95 0x9348, 7, 0, 0, 7,
96 0x8809, 7, 0, 0, 7,
97 0x0000, 0, 0, 0, 0 /* (end of table marker) */
98 };
99
100 /*-------------------------------------------------------------------*/
101 /* TapeCommandTable */
102 /* */
103 /* Specific supported CCW codes for each device type. Index is */
104 /* fetched by TapeCommandIsValid from "TapeDevtypeList[ n+1 ]". */
105 /* */
106 /*-------------------------------------------------------------------*/
107
108 BYTE* TapeCommandTable [] =
109 {
110 TapeCommands3410, /* 0 3410/3411 */
111 TapeCommands3420, /* 1 3420 */
112 TapeCommands3422, /* 2 3422 */
113 TapeCommands3430, /* 3 3430 */
114 TapeCommands3480, /* 4 3480 (Maybe all 38K Tapes) */
115 TapeCommands3490, /* 5 3490 */
116 TapeCommands3590, /* 6 3590 */
117 TapeCommands9347, /* 7 9347 (Maybe all streaming tapes) */
118 NULL
119 };
120
121 /*-------------------------------------------------------------------*/
122 /* TapeSenseTable */
123 /* */
124 /* SENSE function routing table. Index is fetched by 'build_senseX' */
125 /* function from table entry "TapeDevtypeList[ i+4 ]". */
126 /*-------------------------------------------------------------------*/
127
128 TapeSenseFunc* TapeSenseTable [] =
129 {
130 build_sense_3410, /* 0 3410/3411 */
131 build_sense_3420, /* 1 3420 */
132 build_sense_3422, /* 2 3422 */
133 build_sense_3430, /* 3 3430 */
134 build_sense_3480_etal, /* 4 3480 (Maybe all 38K Tapes) */
135 build_sense_3490, /* 5 3490 */
136 build_sense_3590, /* 6 3590 */
137 build_sense_Streaming, /* 7 9347 (Maybe all streaming tapes) */
138 NULL
139 };
140
141 /*-------------------------------------------------------------------*/
142 /* CCW opcode Validity Tables by Device Type */
143 /*-------------------------------------------------------------------*/
144 /* */
145 /* The below tables are used by 'TapeCommandIsValid' to determine */
146 /* if a CCW code is initially valid or not for the given device. */
147 /* */
148 /* 0: Command is NOT valid */
149 /* * 1: Command is Valid, Tape MUST be loaded */
150 /* * 2: Command is Valid, Tape NEED NOT be loaded */
151 /* 3: Command is Valid, But is a NO-OP (return CE+DE now) */
152 /* 4: Command is Valid, But is a NO-OP (for virtual tapes) */
153 /* * 5: Command is Valid, Tape MUST be loaded (add DE to status) */
154 /* */
155 /* * Note that CCWs codes marked as valid might still get rejected */
156 /* upon more stringent validity testing done by the actual CCW */
157 /* processing function itself. */
158 /* */
159 /* SOURCES: */
160 /* */
161 /* GX20-1850-2 "S/370 Reference Summary" (3410/3411/3420) */
162 /* GX20-0157-1 "370/XA Reference Summary" (3420/3422/3430/3480) */
163 /* GA33-1510-0 "S/370 Model 115 FC" (3410/3411) */
164 /* */
165 /* Ivan Warren, 2003-02-24 */
166 /*-------------------------------------------------------------------*/
167
168 BYTE TapeCommands3410 [256] =
169 {
170 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
171 0,1,1,1,2,0,0,5,0,0,0,0,1,0,0,5, /* 00 */
172 0,0,0,4,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */
173 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 20 */
174 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 30 */
175 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */
176 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
177 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 60 */
178 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 70 */
179 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */
180 0,0,0,4,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */
181 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* A0 */
182 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* B0 */
183 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* C0 */
184 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* D0 */
185 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */
186 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* F0 */
187 };
188
189 BYTE TapeCommands3420 [256] =
190 {
191 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
192 0,1,1,1,2,0,0,5,0,0,0,2,1,0,0,5, /* 00 */
193 0,0,0,4,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */
194 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 20 */
195 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 30 */
196 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */
197 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
198 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 60 */
199 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 70 */
200 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 80 */
201 0,0,0,4,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */
202 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* A0 */
203 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* B0 */
204 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* C0 */
205 0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0, /* D0 */
206 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */
207 0,0,0,2,4,0,0,0,0,0,0,0,0,2,0,0 /* F0 */
208 };
209
210 BYTE TapeCommands3422 [256] =
211 {
212 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
213 0,1,1,1,2,0,0,5,0,0,0,2,1,0,0,5, /* 00 */
214 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 10 */
215 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 20 */
216 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 30 */
217 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */
218 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
219 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */
220 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */
221 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, /* 80 */
222 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */
223 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */
224 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */
225 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */
226 0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0, /* D0 */
227 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */
228 0,0,0,2,4,0,0,0,0,0,0,0,0,2,0,0 /* F0 */
229 };
230
231 BYTE TapeCommands3430 [256] =
232 {
233 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
234 0,1,1,1,2,0,0,5,0,0,0,2,1,0,0,5, /* 00 */
235 0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */
236 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 20 */
237 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 30 */
238 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */
239 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
240 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */
241 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */
242 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */
243 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */
244 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */
245 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */
246 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */
247 0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0, /* D0 */
248 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */
249 0,0,0,2,4,0,0,0,0,0,0,0,0,2,0,0 /* F0 */
250 };
251
252 BYTE TapeCommands3480 [256] =
253 {
254 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
255 3,1,1,1,2,0,0,5,0,0,0,0,1,0,0,5, /* 00 */
256 0,0,1,3,0,0,0,1,0,0,0,0,0,0,0,1, /* 10 */
257 0,0,1,3,2,0,0,1,0,0,0,3,0,0,0,1, /* 20 */
258 0,0,0,3,2,0,0,1,0,0,0,3,0,0,0,1, /* 30 */
259 0,0,0,1,0,0,0,0,0,0,0,2,0,0,0,1, /* 40 */
260 0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0, /* 50 */
261 0,0,0,3,2,0,0,0,0,0,0,3,0,0,0,0, /* 60 */
262 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* 70 */
263 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */
264 0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,2, /* 90 */
265 0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,2, /* A0 */
266 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* B0 */
267 0,0,0,2,0,0,0,2,0,0,0,3,0,0,0,0, /* C0 */
268 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* D0 */
269 0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0, /* E0 */
270 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* F0 */
271 };
272
273 BYTE TapeCommands3490 [256] =
274 {
275 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
276 3,1,1,1,2,0,0,5,0,0,0,0,1,0,0,5, /* 00 */
277 0,0,1,3,0,0,0,1,0,0,0,0,0,0,0,1, /* 10 */
278 0,0,1,3,2,0,0,1,0,0,0,3,0,0,0,1, /* 20 */
279 0,0,0,3,2,0,0,1,0,0,0,3,0,0,2,1, /* 30 */
280 0,0,0,1,0,0,0,0,0,0,0,2,0,0,2,1, /* 40 */
281 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* 50 */
282 0,0,0,3,2,0,0,0,0,0,0,3,0,0,0,0, /* 60 */
283 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* 70 */
284 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */
285 0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,2, /* 90 */
286 0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,2, /* A0 */
287 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* B0 */
288 0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0, /* C0 */
289 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* D0 */
290 0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0, /* E0 */
291 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0 /* F0 */
292 };
293
294 BYTE TapeCommands3590 [256] =
295 {
296 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
297 3,1,1,1,2,0,1,5,0,0,1,0,1,0,0,5, /* 00 */
298 0,0,1,3,0,0,0,1,0,0,0,0,0,0,0,1, /* 10 */
299 0,0,1,3,2,0,0,1,0,0,0,3,0,0,0,1, /* 20 */
300 0,0,0,3,2,0,0,1,0,0,0,3,0,0,2,1, /* 30 */
301 0,0,0,1,0,0,0,0,0,0,0,2,0,0,2,1, /* 40 */
302 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* 50 */
303 0,0,1,3,2,0,0,0,0,0,0,3,0,0,0,0, /* 60 */
304 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* 70 */
305 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */
306 0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,2, /* 90 */
307 0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,2, /* A0 */
308 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* B0 */
309 0,0,2,2,0,0,0,2,0,0,0,0,0,0,0,2, /* C0 */
310 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* D0 */
311 0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0, /* E0 */
312 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0 /* F0 */
313 };
314
315 BYTE TapeCommands9347 [256] =
316 {
317 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
318 0,1,1,1,2,0,0,5,0,0,0,2,1,0,0,5, /* 00 */
319 0,0,0,4,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */
320 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 20 */
321 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 30 */
322 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */
323 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
324 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 60 */
325 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 70 */
326 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 80 */
327 0,0,0,4,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */
328 0,0,0,4,2,0,0,0,0,0,0,4,0,0,0,0, /* A0 */
329 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* B0 */
330 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* C0 */
331 0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0, /* D0 */
332 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */
333 0,0,0,2,4,0,0,0,0,0,0,0,0,2,0,0 /* F0 */
334 };
335
336 /*-------------------------------------------------------------------*/
337 /* Ivan Warren 20040227 */
338 /* */
339 /* This table is used by channel.c to determine if a CCW code */
340 /* is an immediate command or not. */
341 /* */
342 /* The tape is addressed in the DEVHND structure as 'DEVIMM immed' */
343 /* */
344 /* 0: ("false") Command is *NOT* an immediate command */
345 /* 1: ("true") Command *IS* an immediate command */
346 /* */
347 /* Note: An immediate command is defined as a command which returns */
348 /* CE (channel end) during initialization (that is, no data is */
349 /* actually transfered). In this case, IL is not indicated for a */
350 /* Format 0 or Format 1 CCW when IL Suppression Mode is in effect. */
351 /* */
352 /*-------------------------------------------------------------------*/
353
354 BYTE TapeImmedCommands [256] =
355 {
356 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
357 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1, /* 00 */
358 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */
359 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 20 */
360 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 30 */
361 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, /* 40 */
362 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 50 */
363 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 60 */
364 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1, /* 70 */ /* Adrian Trenkwalder - 77 was 1 */
365 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 80 */
366 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0, /* 90 */
367 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0, /* A0 */
368 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1, /* B0 */
369 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1, /* C0 */
370 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1, /* D0 */
371 0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1, /* E0 */
372 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1 /* F0 */
373 };
374
375 /*-------------------------------------------------------------------*/
376 /* TapeCommandIsValid (Ivan Warren 20030224) */
377 /*-------------------------------------------------------------------*/
378 /* */
379 /* Determine if a CCW code is valid for the Device */
380 /* */
381 /* rc 0: is *NOT* valid */
382 /* rc 1: is Valid, tape MUST be loaded */
383 /* rc 2: is Valid, tape NEED NOT be loaded */
384 /* rc 3: is Valid, But is a NO-OP (Return CE+DE now) */
385 /* rc 4: is Valid, But is a NO-OP for virtual tapes */
386 /* rc 5: is Valid, Tape Must be loaded - Add DE to status */
387 /* rc 6: is Valid, Tape load attempted - but not an error */
388 /* (used for sense and no contingency allegiance exists) */
389 /* */
390 /*-------------------------------------------------------------------*/
TapeCommandIsValid(BYTE code,U16 devtype,BYTE * rustat)391 int TapeCommandIsValid (BYTE code, U16 devtype, BYTE *rustat)
392 {
393 int i, rc, tix = 0, devtfound = 0;
394
395 /*
396 ** Find the D/T in the table
397 ** If not found, treat as invalid CCW code
398 */
399
400 *rustat = 0;
401
402 for (i = 0; TapeDevtypeList[i] != 0; i += TAPEDEVTYPELIST_ENTRYSIZE)
403 {
404 if (TapeDevtypeList[i] == devtype)
405 {
406 devtfound = 1;
407 tix = TapeDevtypeList[i+1];
408
409 if (TapeDevtypeList[i+2])
410 {
411 *rustat |= CSW_UC;
412 }
413 if (TapeDevtypeList[i+3])
414 {
415 *rustat |= CSW_CUE;
416 }
417 break;
418 }
419 }
420
421 if (!devtfound)
422 return 0;
423
424 rc = TapeCommandTable[tix][code];
425
426 return rc;
427
428 } /* end function TapeCommandIsValid */
429
430
431 /*********************************************************************/
432 /*********************************************************************/
433 /** **/
434 /** MAIN TAPE CCW PROCESSING FUNCTION **/
435 /** **/
436 /*********************************************************************/
437 /*********************************************************************/
438
439 #if defined( OPTION_TAPE_AUTOMOUNT )
440 static TAMDIR* findtamdir( int rej, int minlen, const char* pszDir );
441 #endif
442
tapedev_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)443 void tapedev_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags,
444 BYTE chained, U16 count, BYTE prevcode, int ccwseq,
445 BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual)
446 {
447 int rc; /* Return code */
448 int len; /* Length of data block */
449 long num; /* Number of bytes to read */
450 int drc; /* code disposition */
451 BYTE rustat; /* Addl CSW stat on Rewind Unload */
452
453 UNREFERENCED(ccwseq);
454
455 /* Reset flags at start of CCW chain */
456 if (dev->ccwseq == 0)
457 {
458 dev->supvr_inhibit = 0; /* (reset to default mode) */
459 dev->write_immed = 0; /* (reset to default mode) */
460 dev->tapssdlen = 0; /* (clear all subsys data) */
461 }
462
463 /* If this is a data-chained READ, then return any data remaining
464 in the buffer which was not used by the previous CCW */
465 if (chained & CCW_FLAGS_CD)
466 {
467 if (IS_CCW_RDBACK(code))
468 {
469 /* We don't need to move anything in this case - just set length */
470 }
471 else
472 {
473 memmove (iobuf, iobuf + dev->curbufoff, dev->curblkrem);
474 }
475 RESIDUAL_CALC (dev->curblkrem);
476 dev->curblkrem -= num;
477 dev->curbufoff = num;
478 *unitstat = CSW_CE | CSW_DE;
479 return;
480 }
481
482 /* Command reject if data chaining and command is not a read type */
483 if ((flags & CCW_FLAGS_CD) &&
484 !(IS_CCW_READ(code) || IS_CCW_RDBACK(code)))
485 {
486 logmsg(_("HHCTA072E Data chaining not supported for CCW %2.2X\n"),
487 code);
488 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
489 return;
490 }
491
492 /* Command reject if command is not Read Subsystem Data command
493 if the previous one was a Perform Subsystem Function command
494 that prepared some subsystem data for subsequent reading
495 */
496 if (0x77 == prevcode && dev->tapssdlen && 0x3E != code)
497 {
498 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
499 return;
500 }
501
502 /* Early determination of CCW validity via TapeCommandTable lookup... */
503
504 drc = TapeCommandIsValid (code, dev->devtype, &rustat);
505
506 switch (drc)
507 {
508 default: /* Should NOT occur! */
509
510 ASSERT(0); // (fall thru to case 0 = unsupported)
511
512 case 0: /* Unsupported CCW code for given device-type */
513
514 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
515 return;
516
517 case 1: /* Valid - Tape MUST be loaded */
518 break;
519
520 case 2: /* Valid - Tape NEED NOT be loaded */
521 break;
522
523 case 3: /* Valid - But is a NO-OP (return CE+DE now) */
524
525 /* Command reject if the volume is currently fenced */
526 if (dev->fenced)
527 {
528 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
529 return;
530 }
531
532 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
533 return;
534
535 case 4: /* Valid, But is a NO-OP (for virtual tapes) */
536
537 /* Command reject if the volume is currently fenced */
538 if (dev->fenced)
539 {
540 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
541 return;
542 }
543
544 /* If non-virtual (SCSI) then further processing required */
545 if (dev->tapedevt == TAPEDEVT_SCSITAPE)
546 break;
547
548 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
549 return;
550
551 case 5: /* Valid - Tape MUST be loaded (add DE to status) */
552 break;
553 }
554 // end switch (drc)
555
556 /* Verify a tape is loaded if that is required for this CCW... */
557
558 if ((1 == drc || 5 == drc) && // (tape MUST be loaded?)
559 (dev->fd < 0 || TAPEDEVT_SCSITAPE == dev->tapedevt)) // (no tape loaded or non-virtual?)
560 {
561 *residual = count;
562
563 /* Error if tape unloaded */
564 if (!strcmp (dev->filename, TAPE_UNLOADED))
565 {
566 build_senseX (TAPE_BSENSE_TAPEUNLOADED, dev, unitstat, code);
567 return;
568 }
569
570 /* Open the device file if necessary */
571 if (dev->fd < 0)
572 {
573 rc = dev->tmh->open( dev, unitstat, code );
574
575 if (rc < 0) /* Did open fail? */
576 {
577 return; /* Yes, exit with unit status */
578 }
579 }
580
581 /* Error if tape is not loaded */
582 if (!dev->tmh->tapeloaded( dev, unitstat, code ))
583 {
584 build_senseX (TAPE_BSENSE_TAPEUNLOADED, dev, unitstat, code);
585 return;
586 }
587 }
588
589 /* Process depending on CCW opcode */
590 switch (code) {
591
592 /*---------------------------------------------------------------*/
593 /* MODE SET (pre-3480 and earlier drives) */
594 /*---------------------------------------------------------------*/
595 /* Patch to no-op modeset 1 (7-track) commands - */
596 /* causes VM problems */
597 /* Andy Norrie 2002/10/06 */
598 case 0x13:
599 case 0x23:
600 case 0x33:
601 case 0x3B:
602 case 0x53:
603 case 0x63:
604 case 0x6B:
605 // case 0x73: // Mode Set (7-track 556/Odd/Normal) for 3420-3/5/7
606 // with 7-track feature installed, No-op for 3420-2/4/6
607 // and 3480, Invalid for 3422/3430, "Set Interface
608 // Identifier" for 3490 and later. NOTE: 3480 and earlier
609 // interpretation handled by command-table; 3490 and
610 // and later handled further below.
611 case 0x7B:
612 case 0x93:
613 case 0xA3:
614 case 0xAB:
615 case 0xB3:
616 case 0xBB:
617 // case 0xC3: // Mode Set (9-track 1600 bpi) for models earlier than
618 // 3480, "Set Tape-Write-Immediate" for 3480 and later.
619 // NOTE: handled by command-table for all models earlier
620 // than 3480; 3480 and later handled further below.
621 case 0xCB: /* 9-track 800 bpi */
622 case 0xD3: /* 9-track 6250 bpi */
623 case 0xEB: /* invalid mode set issued by DOS/VS */
624 {
625 build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code);
626 break;
627 }
628
629 /*---------------------------------------------------------------*/
630 /* WRITE */
631 /*---------------------------------------------------------------*/
632 case 0x01:
633 {
634 /* Command reject if the volume is currently fenced */
635 if (dev->fenced)
636 {
637 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
638 break;
639 }
640
641 /* Unit check if tape is write-protected */
642 if (dev->readonly || dev->tdparms.logical_readonly)
643 {
644 build_senseX (TAPE_BSENSE_WRITEPROTECT, dev, unitstat, code);
645 break;
646 }
647
648 /* Update matrix display if needed */
649 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
650 {
651 dev->tapedisptype = TAPEDISPTYP_IDLE;
652 UpdateDisplay( dev );
653 }
654
655 /* Assign a unique Message Id for this I/O if needed */
656 INCREMENT_MESSAGEID(dev);
657
658 /* Write a block to the tape according to device type */
659 if ((rc = dev->tmh->write( dev, iobuf, count, unitstat, code)) < 0)
660 break; // (error)
661
662 *residual = 0;
663
664 /* Perform flush/sync and/or set normal completion status */
665 if (0
666 || !dev->write_immed
667 || (rc = dev->tmh->sync( dev, unitstat, code )) == 0
668 )
669 build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code );
670
671 break;
672 }
673
674 /*---------------------------------------------------------------*/
675 /* READ FORWARD (3590 only) */
676 /*---------------------------------------------------------------*/
677 case 0x06:
678 {
679 /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide
680
681 5.2.1 Separate Channel Commands for IPL Read and Normal Read
682
683 On IBM 3480/3490 tape devices there is only one Read Forward
684 CCW, the X'02' command code. This CCW is used to perform
685 not only normal read operations but also an IPL Read from
686 tape, for example, DFSMSdss Stand-Alone Restore. When the
687 CCW is used as an IPL Read, it is not subject to resetting
688 event notification, by definition. Because there is only
689 one Read Forward CCW, it cannot be subject to resetting event
690 notification on IBM 3480 and 3490 devices.
691
692 To differentiate between an IPL Read and a normal read
693 forward operation, the X'02' command code has been redefined
694 to be the IPL Read CCW, and a new X'06' command code has been
695 defined to be the Read Forward CCW. The new Read Forward
696 CCW, X'06', is subject to resetting event notification, as
697 should be the case for normal read CCWs issued by applications
698 or other host software.
699 */
700
701 // PROGRAMMING NOTE: I'm not sure what they mean by "resetting
702 // event notification" above, but for now we'll just FALL THROUGH
703 // to the below IPL READ logic...
704 }
705
706 // (purposely FALL THROUGH to below IPL READ logic for now)
707
708 /*---------------------------------------------------------------*/
709 /* IPL READ (non-3590) */
710 /*---------------------------------------------------------------*/
711 case 0x02:
712 {
713 /* Command reject if the volume is currently fenced */
714 if (dev->fenced)
715 {
716 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
717 break;
718 }
719
720 /* Update matrix display if needed */
721 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
722 {
723 dev->tapedisptype = TAPEDISPTYP_IDLE;
724 UpdateDisplay( dev );
725 }
726
727 /* Assign a unique Message Id for this I/O if needed */
728 INCREMENT_MESSAGEID(dev);
729
730 /* Read a block from the tape according to device type */
731 /* Exit with unit check status if read error condition */
732 if ((len = dev->tmh->read( dev, iobuf, unitstat, code)) < 0)
733 break; // (error)
734
735 /* Calculate number of bytes to read and residual byte count */
736 RESIDUAL_CALC (len);
737
738 /* Save size and offset of data not used by this CCW */
739 dev->curblkrem = len - num;
740 dev->curbufoff = num;
741
742 /* Exit with unit exception status if tapemark was read */
743 if (len == 0)
744 build_senseX (TAPE_BSENSE_READTM, dev, unitstat, code);
745 else
746 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
747
748 break;
749 }
750
751 /*---------------------------------------------------------------*/
752 /* CONTROL NO-OPERATION */
753 /*---------------------------------------------------------------*/
754 case 0x03:
755 {
756 /* Command reject if the volume is currently fenced */
757 if (dev->fenced)
758 {
759 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
760 break;
761 }
762
763 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
764 break;
765 }
766
767 /*---------------------------------------------------------------*/
768 /* SENSE */
769 /*---------------------------------------------------------------*/
770 case 0x04:
771 {
772 /* Calculate residual byte count */
773 RESIDUAL_CALC (dev->numsense);
774
775 /* If we don't already have some sense already pre-built
776 and ready and waiting, then we'll have to build it fresh
777 for this call... Otherwise, we use whatever we already
778 have waiting for them pre-built from a previous call...
779 */
780 if (!dev->sns_pending)
781 build_senseX (TAPE_BSENSE_UNSOLICITED, dev, unitstat, code);
782
783 *unitstat = CSW_CE|CSW_DE; /* Need to do this ourselves as */
784 /* we might not have gone thru */
785 /* build_senseX... */
786
787 /* Copy device sense bytes to channel I/O buffer, clear
788 them for the next time, and then finally, reset the
789 Contengent Allegiance condition... */
790 memcpy (iobuf, dev->sense, num);
791 memset (dev->sense, 0, sizeof(dev->sense));
792 dev->sns_pending = 0;
793
794 break;
795 }
796
797 /*---------------------------------------------------------------*/
798 /* READ FORWARD (3590 only) */
799 /*---------------------------------------------------------------*/
800 // case 0x06:
801 // {
802 // (handled by case 0x02: IPL READ)
803 // }
804
805 /*---------------------------------------------------------------*/
806 /* REWIND */
807 /*---------------------------------------------------------------*/
808 case 0x07:
809 {
810 /* Update matrix display if needed */
811 if ( TAPEDISPTYP_IDLE == dev->tapedisptype ||
812 TAPEDISPTYP_WAITACT == dev->tapedisptype )
813 {
814 dev->tapedisptype = TAPEDISPTYP_REWINDING;
815 UpdateDisplay( dev );
816 }
817
818 /* Assign a unique Message Id for this I/O if needed */
819 INCREMENT_MESSAGEID(dev);
820
821 /* Do the rewind */
822 rc = dev->tmh->rewind( dev, unitstat, code);
823
824 /* Update matrix display if needed */
825 if ( TAPEDISPTYP_REWINDING == dev->tapedisptype )
826 {
827 dev->tapedisptype = TAPEDISPTYP_IDLE;
828 UpdateDisplay( dev );
829 }
830
831 /* Check for error */
832 if (rc < 0)
833 {
834 dev->fenced = 1;
835 break;
836 }
837
838 dev->eotwarning = 0;
839 dev->fenced = 0;
840
841 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
842 break;
843 }
844
845 /*---------------------------------------------------------------*/
846 /* READ PREVIOUS (3590) */
847 /*---------------------------------------------------------------*/
848 case 0x0A:
849 {
850 /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide
851
852 5.2.2 Read Previous to Replace Read Backward:
853
854 The ESCON-attached Magstar tape drive does not support the
855 Read Backward CCW (command code, X'0C'). It supports a new
856 Read Previous CCW that allows processing of an IBM 3590 High
857 Performance Tape Cartridge in the backward direction without
858 the performance penalties that exist with the Read Backward
859 CCW. IBM 3480 and 3490 devices had to reread the physical
860 block from the medium for each request of a logical block.
861 The Magstar tape drive retains the physical block in the
862 device buffer and satisfies any subsequent Read Previous from
863 the buffer, similar to how Read Forward operates. The Read
864 Previous CCW operates somewhat like the Read Backward CCW
865 in that it can be used to process the volumes in the backward
866 direction. It is different from the Read Backward, however,
867 because the data is transferred to the host in the same order
868 in which it was written, rather than in reverse order like
869 Read Backward.
870 */
871
872 /* SG24-2594 IBM 3590 Multiplatform Implementation
873
874 5.1.2 New and Changed Read Channel Commands
875
876 [...] That is, the Read Backward command's data address
877 will point to the end of the storage area, while a Read
878 Previous command points to the beginning of the storage
879 area...
880 */
881
882 // PROGRAMMING NOTE: luckily, channel.c's buffer handling
883 // causes transparent handling of Read Backward/Reverse,
884 // so the above buffer alignment and data transfer order
885 // is not a concern for us here.
886
887 // PROGRAMMING NOTE: until we can add support to Hercules
888 // allowing direct SCSI i/o (so that we can issue the 'Read
889 // Reverse' command directly to the SCSI device), we will
890 // simply FALL THROUGH to our existing "Read Backward" logic.
891 }
892
893 // (purposely FALL THROUGH to the 'READ BACKWARD' logic below)
894
895 /*---------------------------------------------------------------*/
896 /* READ BACKWARD */
897 /*---------------------------------------------------------------*/
898 case 0x0C:
899 {
900 /* Update matrix display if needed */
901 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
902 {
903 dev->tapedisptype = TAPEDISPTYP_IDLE;
904 UpdateDisplay( dev );
905 }
906
907 /* Backspace to previous block according to device type */
908 /* Exit with unit check status if error condition */
909 if ((rc = dev->tmh->bsb( dev, unitstat, code )) < 0)
910 break; // (error)
911
912 /* Exit with unit exception status if tapemark was sensed */
913 if (rc == 0)
914 {
915 *residual = 0;
916 build_senseX (TAPE_BSENSE_READTM, dev, unitstat, code);
917 break;
918 }
919
920 /* Assign a unique Message Id for this I/O if needed */
921 INCREMENT_MESSAGEID(dev);
922
923 /* Now read in a forward direction the actual data block
924 we just backspaced over, and exit with unit check status
925 on any read error condition
926 */
927 if ((len = dev->tmh->read( dev, iobuf, unitstat, code )) < 0)
928 break; // (error)
929
930 /* Calculate number of bytes to read and residual byte count */
931 RESIDUAL_CALC (len);
932
933 /* Save size and offset of data not used by this CCW */
934 dev->curblkrem = len - num;
935 dev->curbufoff = num;
936
937 /* Backspace to previous block according to device type,
938 and exit with unit check status if error condition */
939 if ((rc = dev->tmh->bsb( dev, unitstat, code )) < 0)
940 break; // (error)
941
942 /* Set normal status */
943 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
944 break;
945
946 } /* End case 0x0C: READ BACKWARD */
947
948 /*---------------------------------------------------------------*/
949 /* REWIND UNLOAD */
950 /*---------------------------------------------------------------*/
951 case 0x0F:
952 {
953 /* Update matrix display if needed */
954 if ( dev->tdparms.displayfeat )
955 {
956 if ( TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype )
957 {
958 dev->tapedisptype = TAPEDISPTYP_MOUNT;
959 dev->tapedispflags |= TAPEDISPFLG_REQAUTOMNT;
960 strlcpy( dev->tapemsg1, dev->tapemsg2, sizeof(dev->tapemsg1) );
961 }
962 else if ( TAPEDISPTYP_UNMOUNT == dev->tapedisptype )
963 {
964 dev->tapedisptype = TAPEDISPTYP_IDLE;
965 }
966 }
967
968 if ( TAPEDISPTYP_IDLE == dev->tapedisptype ||
969 TAPEDISPTYP_WAITACT == dev->tapedisptype )
970 {
971 dev->tapedisptype = TAPEDISPTYP_UNLOADING;
972 UpdateDisplay( dev );
973 }
974
975 /* Assign a unique Message Id for this I/O if needed */
976 INCREMENT_MESSAGEID(dev);
977
978 /* Do the Rewind-Unload */
979 #if defined(OPTION_SCSI_TAPE)
980 if ( TAPEDEVT_SCSITAPE == dev->tapedevt )
981 int_scsi_rewind_unload( dev, unitstat, code );
982 else
983 #endif
984 {
985 dev->tmh->close(dev);
986 *unitstat=0;
987 }
988
989 /* Update matrix display if needed */
990 if ( TAPEDISPTYP_UNLOADING == dev->tapedisptype )
991 {
992 dev->tapedisptype = TAPEDISPTYP_IDLE;
993 UpdateDisplay( dev );
994 }
995
996 if ((*unitstat & CSW_UC) != 0) // (did it work?)
997 break; // (no it didn't)
998
999 dev->curfilen = 1;
1000 dev->nxtblkpos = 0;
1001 dev->prvblkpos = -1;
1002 dev->eotwarning = 0;
1003 // dev->fenced = 0; // (handler already did this)
1004
1005 /* Update matrix display */
1006 UpdateDisplay( dev );
1007
1008 build_senseX(TAPE_BSENSE_RUN_SUCCESS,dev,unitstat,code);
1009
1010 if ( dev->als )
1011 {
1012 TID dummy_tid;
1013 char thread_name[64];
1014 snprintf(thread_name,sizeof(thread_name),
1015 "autoload wait for %4.4X tapemount thread",
1016 dev->devnum);
1017 thread_name[sizeof(thread_name)-1] = 0;
1018 create_thread( &dummy_tid, DETACHED,
1019 autoload_wait_for_tapemount_thread,
1020 dev, thread_name );
1021 }
1022
1023 ReqAutoMount( dev );
1024 break;
1025
1026 } /* End case 0x0F: REWIND UNLOAD */
1027
1028 /*---------------------------------------------------------------*/
1029 /* READ BUFFER (3480 and later) */
1030 /*---------------------------------------------------------------*/
1031 case 0x12:
1032 {
1033 /* GA32-0127 IBM 3490E Hardware Reference
1034
1035 Read Buffer (X'12')
1036
1037 The Read Buffer command transfers data from the control unit
1038 to the channel if any buffered write data is in the control
1039 unit's buffer. For each Read Buffer command completed, the
1040 controlling computer retrieves one block of data in last-in/
1041 first-out (LIFO) sequence until the buffer for the addressed
1042 tape drive is empty. The controlling computer usually issues
1043 this command when the tape drive or subsystem malfunctions
1044 and cannot write data from the buffer to the tape.
1045 */
1046
1047 /* Command reject if the volume is currently fenced */
1048 if (dev->fenced)
1049 {
1050 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1051 break;
1052 }
1053
1054 // PROGRAMMING NOTE: until we can add support for performing
1055 // SCSI i/o directly to the actual real device, we simply do
1056 // the same thing for non-virtual devices as we do for virtual
1057 // ones: we force-flush the data to the device (i.e. sync)
1058 // and then tell the truth: that there's zero bytes of data
1059 // still buffered (which is true if we just flushed it all)
1060
1061 // Once we add direct SCSI i/o support though, we can change
1062 // the below to do an actual read-buffer SCSI command for
1063 // non-virtual devices. (We will still always need the below
1064 // for virtual devices though)
1065
1066 /* Assign a unique Message Id for this I/O if needed */
1067 INCREMENT_MESSAGEID(dev);
1068
1069 // Perform flush/sync; exit on error...
1070 if ((rc = dev->tmh->sync( dev, unitstat, code )) < 0)
1071 break; // (i/o error)
1072
1073 // Flush complete. Our buffer is now empty. Tell them that.
1074 RESIDUAL_CALC (0);
1075 dev->curblkrem = 0;
1076 dev->curbufoff = 0;
1077 break;
1078 }
1079
1080 /*---------------------------------------------------------------*/
1081 /* ERASE GAP */
1082 /*---------------------------------------------------------------*/
1083 case 0x17:
1084 {
1085 /* Command reject if the volume is currently fenced */
1086 if (dev->fenced)
1087 {
1088 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1089 break;
1090 }
1091
1092 /* Unit check if tape is write-protected */
1093 if (dev->readonly || dev->tdparms.logical_readonly)
1094 {
1095 build_senseX (TAPE_BSENSE_WRITEPROTECT, dev, unitstat, code);
1096 break;
1097 }
1098
1099 /* Update matrix display if needed */
1100 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
1101 {
1102 dev->tapedisptype = TAPEDISPTYP_IDLE;
1103 UpdateDisplay( dev );
1104 }
1105
1106 /* Assign a unique Message Id for this I/O if needed */
1107 INCREMENT_MESSAGEID(dev);
1108
1109 /* Do the ERG; exit if error */
1110 if ((rc = dev->tmh->erg( dev, unitstat, code )) < 0)
1111 break; // (error)
1112
1113 /* Perform flush/sync and/or set normal completion status */
1114 if (0
1115 || !dev->write_immed
1116 || (rc = dev->tmh->sync( dev, unitstat, code )) == 0
1117 )
1118 build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code );
1119
1120 break;
1121 }
1122
1123 /*---------------------------------------------------------------*/
1124 /* WRITE TAPE MARK */
1125 /*---------------------------------------------------------------*/
1126 case 0x1F:
1127 {
1128 /* Command reject if the volume is currently fenced */
1129 if (dev->fenced)
1130 {
1131 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1132 break;
1133 }
1134
1135 /* Unit check if tape is write-protected */
1136 if (dev->readonly || dev->tdparms.logical_readonly)
1137 {
1138 build_senseX (TAPE_BSENSE_WRITEPROTECT, dev, unitstat, code);
1139 break;
1140 }
1141
1142 /* Update matrix display if needed */
1143 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
1144 {
1145 dev->tapedisptype = TAPEDISPTYP_IDLE;
1146 UpdateDisplay( dev );
1147 }
1148
1149 /* Assign a unique Message Id for this I/O if needed */
1150 INCREMENT_MESSAGEID(dev);
1151
1152 /* Do the WTM; exit if error */
1153 if ((rc = dev->tmh->wtm(dev,unitstat,code)) < 0)
1154 break; // (error)
1155
1156 dev->curfilen++;
1157
1158 /* Perform flush/sync and/or set normal completion status */
1159 if (0
1160 || !dev->write_immed
1161 || (rc = dev->tmh->sync( dev, unitstat, code )) == 0
1162 )
1163 build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code );
1164
1165 break;
1166 }
1167
1168 /*---------------------------------------------------------------*/
1169 /* READ BLOCK ID */
1170 /*---------------------------------------------------------------*/
1171 case 0x22:
1172 {
1173 BYTE log_blockid [4]; // (temp; BIG-ENDIAN format)
1174 BYTE phys_blockid [4]; // (temp; BIG-ENDIAN format)
1175
1176 int errcode = TAPE_BSENSE_STATUSONLY; // (presume success)
1177
1178 /* Command reject if the volume is currently fenced */
1179 if (dev->fenced)
1180 {
1181 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1182 break;
1183 }
1184
1185 /* Assign a unique Message Id for this I/O if needed */
1186 INCREMENT_MESSAGEID(dev);
1187
1188 /* Calculate number of bytes and residual byte count */
1189 RESIDUAL_CALC( 2 * sizeof(dev->blockid) );
1190
1191 /* Ask media handler for actual value(s)... */
1192 if ((rc = dev->tmh->readblkid( dev, log_blockid, phys_blockid )) < 0)
1193 errcode = TAPE_BSENSE_LOCATEERR;
1194 else
1195 {
1196 /* Copy results to channel I/O buffer... */
1197 memcpy( &iobuf[0], log_blockid, 4 );
1198 memcpy( &iobuf[4], phys_blockid, 4 );
1199 }
1200
1201 /* Set completion status... */
1202 build_senseX( errcode, dev, unitstat, code );
1203 break;
1204 }
1205
1206 /*---------------------------------------------------------------*/
1207 /* READ BUFFERED LOG */
1208 /*---------------------------------------------------------------*/
1209 case 0x24:
1210 {
1211 /* Calculate residual byte count... */
1212
1213 // PROGRAMMING NOTE: technically we *should* have up to
1214 // 64 bytes to give them, but we may not have that many.
1215
1216 /* How many bytes we SHOULD have depends on whether
1217 Extended Buffered Log support is enabled or not */
1218 len = (dev->devchar[8] & 0x01) ? 64 : 32;
1219 RESIDUAL_CALC (len);
1220
1221 /* Clear the device sense bytes */
1222 memset (iobuf, 0, num);
1223
1224 /* Copy device sense bytes to channel I/O buffer */
1225 memcpy (iobuf, dev->sense,
1226 dev->numsense < (U32)num ? dev->numsense : (U32)num);
1227
1228 /* Return unit status */
1229 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
1230 break;
1231 }
1232
1233 /*---------------------------------------------------------------*/
1234 /* BACKSPACE BLOCK */
1235 /*---------------------------------------------------------------*/
1236 case 0x27:
1237 {
1238 /* Command reject if the volume is currently fenced */
1239 if (dev->fenced)
1240 {
1241 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1242 break;
1243 }
1244
1245 /* Update matrix display if needed */
1246 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
1247 {
1248 dev->tapedisptype = TAPEDISPTYP_IDLE;
1249 UpdateDisplay( dev );
1250 }
1251
1252 /* Assign a unique Message Id for this I/O if needed */
1253 INCREMENT_MESSAGEID(dev);
1254
1255 /* Backspace to previous block according to device type,
1256 and exit with unit check status on error condition */
1257 if ((rc = dev->tmh->bsb( dev, unitstat, code )) < 0)
1258 break;
1259
1260 /* Exit with unit exception status if tapemark was sensed */
1261 if (rc == 0)
1262 {
1263 build_senseX (TAPE_BSENSE_READTM, dev, unitstat, code);
1264 break;
1265 }
1266
1267 /* Set normal status */
1268 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
1269 break;
1270 }
1271
1272 /*---------------------------------------------------------------*/
1273 /* BACKSPACE FILE */
1274 /*---------------------------------------------------------------*/
1275 case 0x2F:
1276 {
1277 /* Command reject if the volume is currently fenced */
1278 if (dev->fenced)
1279 {
1280 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1281 break;
1282 }
1283
1284 /* Update matrix display if needed */
1285 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
1286 {
1287 dev->tapedisptype = TAPEDISPTYP_IDLE;
1288 UpdateDisplay( dev );
1289 }
1290
1291 /* Assign a unique Message Id for this I/O if needed */
1292 INCREMENT_MESSAGEID(dev);
1293
1294 /* Backspace to previous file according to device type,
1295 and exit with unit check status on error condition */
1296 if ((rc = dev->tmh->bsf( dev, unitstat, code )) < 0)
1297 break;
1298
1299 /* Set normal status */
1300 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
1301 break;
1302 }
1303
1304 /*---------------------------------------------------------------*/
1305 /* SENSE PATH GROUP ID */
1306 /*---------------------------------------------------------------*/
1307 case 0x34:
1308 {
1309 /* GA32-0127 IBM 3490E Hardware Reference
1310
1311 Sense Path Group ID (X'34')
1312
1313 The Sense Path Group ID command transfers 12 bytes of information
1314 from the control unit to the channel. The first byte (byte 0)
1315 is the path state byte, and the remaining 11 bytes (bytes 1-11)
1316 contain the path-group ID.
1317
1318 The bit assignments in the path state byte (byte 0) are:
1319
1320 ________ ________ ____________________________________
1321 | Bit | Value | Description |
1322 |________|________|____________________________________|
1323 | 0, 1 | | Pathing Status |
1324 |________|________|____________________________________|
1325 | | 00 | Reset |
1326 |________|________|____________________________________|
1327 | | 01 | Reserved |
1328 |________|________|____________________________________|
1329 | | 10 | Ungrouped |
1330 |________|________|____________________________________|
1331 | | 11 | Grouped |
1332 |________|________|____________________________________|
1333 | 2, 3 | | Partitioning State |
1334 |________|________|____________________________________|
1335 | | 00 | Implicitly Enabled |
1336 |________|________|____________________________________|
1337 | | 01 | Reserved |
1338 |________|________|____________________________________|
1339 | | 10 | Disabled |
1340 |________|________|____________________________________|
1341 | | 11 | Explicitly Enabled |
1342 |________|________|____________________________________|
1343 | 4 | | Path Mode |
1344 |________|________|____________________________________|
1345 | | 0 | Single path mode. |
1346 | | 1 | Reserved, invalid for this device. |
1347 |________|________|____________________________________|
1348 | 5-7 | 000 | Reserved |
1349 |________|________|____________________________________|
1350 */
1351
1352 /* Command Reject if Supervisor-Inhibit */
1353 if (dev->supvr_inhibit)
1354 {
1355 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1356 break;
1357 }
1358
1359 /* Command reject if the command is not the ONLY command
1360 in the channel program */
1361 if (chained & CCW_FLAGS_CC)
1362 {
1363 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1364 break;
1365 }
1366
1367 /* Calculate residual byte count */
1368 RESIDUAL_CALC (12);
1369
1370 /* Byte 0 is the path group state byte */
1371 iobuf[0] = dev->pgstat;
1372
1373 /* Bytes 1-11 contain the path group identifier */
1374 if (num > 1)
1375 memcpy (iobuf+1, dev->pgid, num-1);
1376
1377 /* Return unit status */
1378 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
1379 break;
1380
1381 } /* End case 0x34: SENSE PATH GROUP ID */
1382
1383 /*---------------------------------------------------------------*/
1384 /* FORWARD SPACE BLOCK */
1385 /*---------------------------------------------------------------*/
1386 case 0x37:
1387 {
1388 /* Command reject if the volume is currently fenced */
1389 if (dev->fenced)
1390 {
1391 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1392 break;
1393 }
1394
1395 /* Update matrix display if needed */
1396 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
1397 {
1398 dev->tapedisptype = TAPEDISPTYP_IDLE;
1399 UpdateDisplay( dev );
1400 }
1401
1402 /* Assign a unique Message Id for this I/O if needed */
1403 INCREMENT_MESSAGEID(dev);
1404
1405 /* Forward to next block according to device type */
1406 /* Exit with unit check status if error condition */
1407 if ((rc = dev->tmh->fsb( dev, unitstat, code )) < 0)
1408 break;
1409
1410 /* Exit with unit exception status if tapemark was sensed */
1411 if (rc == 0)
1412 {
1413 build_senseX (TAPE_BSENSE_READTM, dev, unitstat, code);
1414 break;
1415 }
1416
1417 /* Set normal status */
1418 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
1419 break;
1420 }
1421
1422 /*---------------------------------------------------------------*/
1423 /* READ SUBSYSTEM DATA (3490/3590) */
1424 /*---------------------------------------------------------------*/
1425 case 0x3E:
1426 {
1427 /* GA32-0127 IBM 3490E Hardware Reference
1428
1429 Read Subsystem Data (X'3E')
1430
1431 The Read Subsystem Data command obtains various types of
1432 information from the 3480/3490 subsystem. The data presented
1433 is dependent on the command immediately preceding the Read
1434 Subsystem Data command in the command chain.
1435
1436 If the preceding command in the command chain is a Perform
1437 Subsystem Function command with the Prepare for Read Subsystem
1438 Data order, the data presented is a function of the sub-order
1439 in the data transferred with the order.
1440 */
1441
1442 /* Command reject if not chained from either a Set Interface
1443 Identifier or Perform Subsystem Function command */
1444 if (!((chained & CCW_FLAGS_CC) && (0x77 == prevcode || 0x73 == prevcode)))
1445 {
1446 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
1447 break;
1448 }
1449
1450 /* Command reject if no subsystem data was prepared
1451 by a previous Perform Subsystem Function command */
1452 if (!dev->tapssdlen) // (any subsystem data?)
1453 {
1454 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1455 break;
1456 }
1457
1458 /* Calculate residual byte count */
1459 RESIDUAL_CALC (dev->tapssdlen);
1460
1461 /* PROGRAMMING NOTE: the Prepare for Read Subsystem Data
1462 order of the previous Perform Subsystem Function command
1463 has already prepared the subsystem data directly in the
1464 channel buffer itself (iobuf), so there isn't any data
1465 that actually needs to be moved/copied; the data is
1466 already sitting in the channel buffer. All we need do
1467 is return a normal status.
1468 */
1469 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
1470 break;
1471
1472 } /* End case 0x3E: READ SUBSYSTEM DATA */
1473
1474 /*---------------------------------------------------------------*/
1475 /* FORWARD SPACE FILE */
1476 /*---------------------------------------------------------------*/
1477 case 0x3F:
1478 {
1479 /* Command reject if the volume is currently fenced */
1480 if (dev->fenced)
1481 {
1482 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1483 break;
1484 }
1485
1486 /* Update matrix display if needed */
1487 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
1488 {
1489 dev->tapedisptype = TAPEDISPTYP_IDLE;
1490 UpdateDisplay( dev );
1491 }
1492
1493 /* Assign a unique Message Id for this I/O if needed */
1494 INCREMENT_MESSAGEID(dev);
1495
1496 /* Forward to next file according to device type */
1497 /* Exit with unit check status if error condition */
1498 if ((rc = dev->tmh->fsf( dev, unitstat, code )) < 0)
1499 break;
1500
1501 /* Set normal status */
1502 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
1503 break;
1504 }
1505
1506 /*---------------------------------------------------------------*/
1507 /* SYNCHRONIZE (3480 or later) */
1508 /*---------------------------------------------------------------*/
1509 case 0x43:
1510 {
1511 /* Command reject if the volume is currently fenced */
1512 if (dev->fenced)
1513 {
1514 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1515 break;
1516 }
1517
1518 /* Update matrix display if needed */
1519 if ( TAPEDISPTYP_WAITACT == dev->tapedisptype )
1520 {
1521 dev->tapedisptype = TAPEDISPTYP_IDLE;
1522 UpdateDisplay( dev );
1523 }
1524
1525 /* Assign a unique Message Id for this I/O if needed */
1526 INCREMENT_MESSAGEID(dev);
1527
1528 /* Do the sync */
1529 if ((rc = dev->tmh->sync( dev, unitstat, code )) == 0)
1530 build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code );
1531
1532 break;
1533 }
1534
1535 #if defined( OPTION_TAPE_AUTOMOUNT )
1536 /*---------------------------------------------------------------*/
1537 /* SET DIAGNOSE -- Special AUTOMOUNT support -- */
1538 /*---------------------------------------------------------------*/
1539 case 0x4B:
1540 {
1541 int argc, i; /* work */
1542 char **argv; /* work */
1543 char newfile [ sizeof(dev->filename) ]; /* work */
1544 char lcss[8]; /* work */
1545
1546 /* Command reject if AUTOMOUNT support not enabled */
1547 if (0
1548 || dev->tapedevt == TAPEDEVT_SCSITAPE
1549 || sysblk.tamdir == NULL
1550 || dev->noautomount
1551 )
1552 {
1553 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
1554 break;
1555 }
1556
1557 /* Command Reject if Supervisor-Inhibit */
1558 if (dev->supvr_inhibit)
1559 {
1560 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1561 break;
1562 }
1563
1564 /* Command Reject if command-chained and i/o length not 1 */
1565 if (flags & CCW_FLAGS_CC)
1566 {
1567 if (count != 1)
1568 {
1569 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1570 break;
1571 }
1572
1573 /* AUTOMOUNT QUERY - part 1 (chained 0xE4 SENSE ID = part 2) */
1574
1575 /* Set normal status but do nothing else; the next CCW
1576 should be a SENSE ID (0xE4) which will do the query */
1577 build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code );
1578 break;
1579 }
1580
1581 /* AUTOMOUNT MOUNT... */
1582
1583 /* Calculate residual byte count */
1584 RESIDUAL_CALC (sizeof(newfile)-1); /* (minus-1 for NULL) */
1585
1586 /* Copy the device's new filename from guest storage */
1587 for (i=0; i < num; i++)
1588 newfile[i] = guest_to_host( iobuf[i] );
1589 newfile[num] = 0;
1590
1591 /* Change "OFFLINE" to "*" (tape unloaded) */
1592 if (strcasecmp (newfile, "OFFLINE") == 0)
1593 strlcpy (newfile, TAPE_UNLOADED, sizeof(newfile));
1594
1595 /* (messages looks better without LCSS if not needed) */
1596 lcss[0] = 0;
1597 if (SSID_TO_LCSS(dev->ssid) != 0)
1598 snprintf( lcss, sizeof(lcss), "%u:", SSID_TO_LCSS(dev->ssid) );
1599 lcss[sizeof(lcss)-1] = 0;
1600
1601 /* Obtain the device lock */
1602 obtain_lock (&dev->lock);
1603
1604 /* Validate the given path... */
1605 if ( strcmp( newfile, TAPE_UNLOADED ) != 0 )
1606 {
1607 TAMDIR *tamdir = NULL;
1608 int minlen = 0;
1609 int rej = 0;
1610
1611 /* (because i hate typing) */
1612 #define HHCTA090E(_file,_reason) \
1613 { \
1614 logmsg(_("HHCTA090E Auto-mount of file \"%s\" on drive %s%4.4X failed: " \
1615 "%s\n"), _file, lcss, dev->devnum, _reason); \
1616 build_senseX (TAPE_BSENSE_TAPELOADFAIL, dev, unitstat, code); \
1617 release_lock (&dev->lock); \
1618 break; \
1619 }
1620
1621 // Resolve given path...
1622 {
1623 char resolve_in [ MAX_PATH ] = {0}; /* (work) */
1624 char resolve_out[ MAX_PATH ] = {0}; /* (work) */
1625
1626 /* (build path to be resolved...) */
1627 if (0
1628 #if defined(_MSVC_)
1629 || newfile[1] == ':' /* (fullpath given?) */
1630 #else /* !_MSVC_ */
1631 || newfile[0] == '/' /* (fullpath given?) */
1632 #endif /* _MSVC_ */
1633 || newfile[0] == '.' /* (relative path given?) */
1634 )
1635 resolve_in[0] = 0; /* (then use just given spec) */
1636 else /* (else prepend with default) */
1637 strlcpy( resolve_in, sysblk.defdir, sizeof(resolve_in) );
1638
1639 /* (finish building path to be resolved) */
1640 strlcat( resolve_in, newfile, sizeof(resolve_in) );
1641
1642 /* (fully resolvable path?) */
1643 if (realpath( resolve_in, resolve_out ) == NULL)
1644 HHCTA090E( resolve_in, "unresolvable path" );
1645
1646 /* Switch to fully resolved path */
1647 strlcpy( newfile, resolve_out, sizeof(newfile) );
1648 }
1649
1650 /* Verify file is in an allowable directory... */
1651 rej = 0; minlen = 0;
1652 while ((tamdir = findtamdir( rej, minlen, newfile )) != NULL)
1653 {
1654 rej = !rej;
1655 minlen = tamdir->len;
1656 }
1657
1658 /* Error if "allowable" directory not found... */
1659 if (!rej)
1660 HHCTA090E( newfile, "impermissible directory" );
1661
1662 /* Verify file exists... */
1663 if (access( newfile, R_OK ) != 0)
1664 HHCTA090E( newfile, "file not found" );
1665 }
1666
1667 /* Prevent accidental re-init'ing of an already loaded tape drive */
1668 if (1
1669 && sysblk.nomountedtapereinit
1670 && strcmp (newfile, TAPE_UNLOADED) != 0
1671 && strcmp (dev->filename, TAPE_UNLOADED) != 0
1672 )
1673 {
1674 logmsg(_("HHCTA091E Tape file auto-mount for drive %s%4.4X rejected: "
1675 "drive not empty\n"),
1676 lcss, dev->devnum);
1677 build_senseX (TAPE_BSENSE_TAPELOADFAIL, dev, unitstat, code);
1678 release_lock (&dev->lock);
1679 break;
1680 }
1681
1682 /* Build re-initialization parameters using new filename */
1683 argc = dev->argc;
1684 argv = malloc (dev->argc * sizeof(char*));
1685
1686 for (i=0; i < argc; i++)
1687 {
1688 if (dev->argv[i])
1689 argv[i] = strdup(dev->argv[i]);
1690 else
1691 argv[i] = NULL;
1692 }
1693
1694 /* (replace filename argument with new filename) */
1695 free( argv[0] );
1696 argv[0] = strdup( newfile );
1697
1698 /* Attempt reinitializing the device using the new filename... */
1699 rc = (int)(dev->hnd->init)( dev, argc, argv );
1700
1701 /* (free temp copy of parms to prevent memory leak) */
1702 for (i=0; i < argc; i++)
1703 if (argv[i])
1704 free(argv[i]);
1705
1706 /* Issue message and set status based on whether it worked or not... */
1707 if (0
1708 || rc < 0
1709 || strfilenamecmp( dev->filename, newfile ) != 0
1710 )
1711 {
1712 // (failure)
1713
1714 if (strcmp( newfile, TAPE_UNLOADED ) == 0)
1715 {
1716 /* (an error message explaining the reason for the
1717 failure should hopefully already have been issued) */
1718 logmsg(_("HHCTA092E Tape file auto-unmount for drive %s%4.4X failed\n"),
1719 lcss, dev->devnum);
1720 }
1721 else
1722 HHCTA090E( newfile, "file not found" ); // (presumed)
1723
1724 /* (the load or unload attempt failed) */
1725 build_senseX (TAPE_BSENSE_TAPELOADFAIL, dev, unitstat, code);
1726 }
1727 else
1728 {
1729 // (success)
1730
1731 if (strcmp( newfile, TAPE_UNLOADED ) == 0)
1732 logmsg(_("HHCTA093I Tape file on drive %s%4.4X auto-unmounted\n"),
1733 lcss, dev->devnum);
1734 else
1735 logmsg(_("HHCTA094I Tape file \"%s\" auto-mounted onto drive %s%4.4X\n"),
1736 dev->filename, lcss, dev->devnum);
1737
1738 /* (save new parms for next time) */
1739 free( dev->argv[0] );
1740 dev->argv[0] = strdup( newfile );
1741
1742 /* (set normal status for this ccw) */
1743 build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code );
1744 }
1745
1746 /* Release the device lock and exit function... */
1747 release_lock (&dev->lock);
1748 break;
1749
1750 } /* End case 0x4B: SET DIAGNOSE */
1751 #endif /* OPTION_TAPE_AUTOMOUNT */
1752
1753 /*---------------------------------------------------------------*/
1754 /* READ MESSAGE ID */
1755 /*---------------------------------------------------------------*/
1756 case 0x4E:
1757 {
1758 /* GA32-0127 IBM 3490E Hardware Reference
1759
1760 Read Message ID (X'4E')
1761
1762 The Read Message ID command is used to read the message identifier
1763 that was assigned by the control unit to commands that indicated
1764 the message-required flag requesting notification when an asynchronous
1765 operation is complete. The Read Message ID command must be chained
1766 directly from the specific command that requested the message
1767 notification or the command will be presented unit check status
1768 with associated sense indicating ERA code 27.
1769
1770 If the Read Message ID command is chained to a specific command
1771 that requests notification, but the command does not result in an
1772 asynchronous operation, the message identifier field returned
1773 will be all zeroes.
1774
1775 The data returned has the following format:
1776
1777 ________ ____________________________________________________
1778 | Byte | Description |
1779 |________|____________________________________________________|
1780 | 0,1 | Length (set to X'000A') |
1781 |________|____________________________________________________|
1782 | 2 | Format (set to X'02') |
1783 |________|____________________________________________________|
1784 | 3 | Message Code |
1785 | | |
1786 | | Value Description |
1787 | | |
1788 | | X'01' Delayed-Response Message |
1789 |________|____________________________________________________|
1790 | 4-7 | Message ID |
1791 | | |
1792 | | This field contains the message identifier |
1793 | | assigned by the control unit to the requested |
1794 | | operation. If the operation was executed by |
1795 | | the subsystem as an immediate operation, this |
1796 | | field contains all zeroes and a later delayed- |
1797 | | response message is not generated. |
1798 |________|____________________________________________________|
1799 | 8 | Flags (set to X'00') |
1800 |________|____________________________________________________|
1801 | 9 | Reserved (set to X'00') |
1802 |________|____________________________________________________|
1803 */
1804
1805 /* Command reject if not chained from a write command */
1806 if (!((chained & CCW_FLAGS_CC) && IS_CCW_WRITE(prevcode)))
1807 {
1808 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1809 break;
1810 }
1811
1812 /* Calculate residual byte count */
1813 RESIDUAL_CALC( 10 );
1814
1815 // PROGRAMMING NOTE: at the moment all of our i/o's are synchronous.
1816 // Thus we always return zero indicating the i/o was not asynchronous.
1817
1818 STORE_HW ( &iobuf[0], 10 ); // 0-1
1819 iobuf[2] = 0x02; // 2
1820 iobuf[3] = 0x01; // 3
1821 STORE_FW ( &iobuf[4], 0 ); // 4-7 (Message Id)
1822 iobuf[8] = 0x00; // 8
1823 iobuf[9] = 0x00; // 9
1824
1825 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat,code);
1826 break;
1827
1828 } /* End case 0x4E: READ MESSAGE ID */
1829
1830 /*---------------------------------------------------------------*/
1831 /* LOCATE BLOCK */
1832 /*---------------------------------------------------------------*/
1833 case 0x4F:
1834 {
1835 U32 locblock; /* Block Id for Locate Block */
1836 int errcode = TAPE_BSENSE_STATUSONLY; /* Presumed success */
1837
1838 /* Command reject if the volume is currently fenced */
1839 if (dev->fenced)
1840 {
1841 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
1842 break;
1843 }
1844
1845 /* Check for minimum count field */
1846 if (count < sizeof(dev->blockid))
1847 {
1848 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1849 break;
1850 }
1851
1852 /* Block to seek */
1853 ASSERT( count >= sizeof(locblock) );
1854 FETCH_FW(locblock, iobuf);
1855
1856 /* Check for invalid/reserved Format Mode bits */
1857 if (0x3590 != dev->devtype)
1858 {
1859 if (0x00C00000 == (locblock & 0x00C00000))
1860 {
1861 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1862 break;
1863 }
1864
1865 /* We only want the Block Number in the low-order 22 bits */
1866 locblock &= 0x003FFFFF;
1867 }
1868
1869 /* Calculate residual byte count */
1870 RESIDUAL_CALC( sizeof(locblock) );
1871
1872 /* Informative message if tracing */
1873 if ( dev->ccwtrace || dev->ccwstep )
1874 logmsg(_("HHCTA081I Locate block 0x%8.8"I32_FMT"X on %s%s%4.4X\n")
1875 ,locblock
1876 ,TAPEDEVT_SCSITAPE == dev->tapedevt ? (char*)dev->filename : ""
1877 ,TAPEDEVT_SCSITAPE == dev->tapedevt ? " = " : ""
1878 ,dev->devnum
1879 );
1880
1881 /* Update display if needed */
1882 if ( TAPEDISPTYP_IDLE == dev->tapedisptype ||
1883 TAPEDISPTYP_WAITACT == dev->tapedisptype )
1884 {
1885 dev->tapedisptype = TAPEDISPTYP_LOCATING;
1886 UpdateDisplay( dev );
1887 }
1888
1889 /* Assign a unique Message Id for this I/O if needed */
1890 INCREMENT_MESSAGEID(dev);
1891
1892 /* Ask media handler to perform the locate... */
1893 if ((rc = dev->tmh->locateblk( dev, locblock, unitstat, code )) < 0)
1894 {
1895 errcode = TAPE_BSENSE_LOCATEERR;
1896 dev->fenced = 1; // (position lost; fence the volume)
1897 }
1898
1899 /* Update display if needed */
1900 if ( TAPEDISPTYP_LOCATING == dev->tapedisptype )
1901 {
1902 dev->tapedisptype = TAPEDISPTYP_IDLE;
1903 UpdateDisplay( dev );
1904 }
1905
1906 /* Set completion status... */
1907 build_senseX( errcode, dev, unitstat, code );
1908 break;
1909
1910 } /* End case 0x4F: LOCATE BLOCK */
1911
1912 /*---------------------------------------------------------------*/
1913 /* SUSPEND MULTIPATH RECONNECTION (3480 and later) */
1914 /*---------------------------------------------------------------*/
1915 case 0x5B:
1916 {
1917 /* GA32-0127 IBM 3490E Hardware Reference
1918
1919 Suspend Multipath Reconnection (X'5B')
1920
1921 The Suspend Multipath Reconnection command performs as a
1922 No-Operation command because all controlling-computer-to-
1923 subsystem operations occur in single-path status.
1924 */
1925
1926 /* Command Reject if Supervisor-Inhibit */
1927 if (dev->supvr_inhibit)
1928 {
1929 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1930 break;
1931 }
1932
1933 /* Set normal status */
1934 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
1935 break;
1936 }
1937
1938 /*---------------------------------------------------------------*/
1939 /* READ MEDIA CHARACTERISTICS (3590 only) */
1940 /*---------------------------------------------------------------*/
1941 case 0x62:
1942 {
1943 /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide
1944
1945 5.2.3 New Read Media Characteristics
1946
1947 The new Read Media Characteristics CCW (command code x'62')
1948 provides up to 256 bytes of information about the media and
1949 formats supported by the Magstar tape drive."
1950 */
1951
1952 // ZZ FIXME: not coded yet.
1953
1954 /* Set command reject sense byte, and unit check status */
1955 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1956 break;
1957 }
1958
1959 /*---------------------------------------------------------------*/
1960 /* READ DEVICE CHARACTERISTICS */
1961 /*---------------------------------------------------------------*/
1962 case 0x64:
1963 {
1964 /* Command reject if device characteristics not available */
1965 if (dev->numdevchar == 0)
1966 {
1967 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
1968 break;
1969 }
1970
1971 /* Calculate residual byte count */
1972 RESIDUAL_CALC (dev->numdevchar);
1973
1974 /* Copy device characteristics bytes to channel buffer */
1975 memcpy (iobuf, dev->devchar, num);
1976
1977 /* Return unit status */
1978 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
1979 break;
1980 }
1981
1982 #if 0
1983 /*---------------------------------------------------------------*/
1984 /* SET INTERFACE IDENTIFIER (3490 and later) */
1985 /*---------------------------------------------------------------*/
1986 case 0x73:
1987 {
1988 // PROGRAMMING NOTE: the 3480 and earlier "Mode Set" interpretation
1989 // of this CCW is handled in the command-table as a no-op; the "Set
1990 // Interface Identifier" interpretation of this CCW for 3490 and
1991 // later model tape drives is *ALSO* handled in the command-table
1992 // as a no-op as well, so there's really no reason for this switch
1993 // case to even exist until such time as we need to support a model
1994 // that happens to require special handling (which is unlikely).
1995
1996 // I'm keeping the code here however for documentation purposes
1997 // only, but of course disabling it from compilation via #if 0.
1998
1999 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
2000 break;
2001 }
2002 #endif
2003
2004 /*---------------------------------------------------------------*/
2005 /* PERFORM SUBSYSTEM FUNCTION */
2006 /*---------------------------------------------------------------*/
2007 case 0x77:
2008 {
2009 BYTE order = iobuf[0];
2010 BYTE flag = iobuf[1];
2011 BYTE parm = iobuf[2];
2012
2013 /* Command Reject if Supervisor-Inhibit */
2014 if (dev->supvr_inhibit)
2015 {
2016 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2017 break;
2018 }
2019
2020 /* The flag byte must be zero for all orders because
2021 none of our supported orders supports a flag byte */
2022 if (PSF_FLAG_ZERO != flag)
2023 {
2024 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2025 break;
2026 }
2027
2028 /* Byte 0 is the PSF order */
2029 switch (order)
2030 {
2031 /*-----------------------------------------------------------*/
2032 /* Activate/Deactivate Forced Error Logging */
2033 /* 0x8000nn / 0x8100nn */
2034 /*-----------------------------------------------------------*/
2035 case PSF_ORDER_AFEL:
2036 case PSF_ORDER_DFEL:
2037 {
2038 BYTE bEnable = (PSF_ORDER_AFEL == order) ? 1 : 0;
2039
2040 /* Calculate residual byte count */
2041 RESIDUAL_CALC (3);
2042
2043 /* Control information length must be 3 bytes long */
2044 /* and the parameter byte must be one or the other */
2045 if ( (count < len)
2046 || ((PSF_ACTION_FEL_IMPLICIT != parm) &&
2047 (PSF_ACTION_FEL_EXPLICIT != parm))
2048 )
2049 {
2050 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
2051 break;
2052 }
2053
2054 /* Enable/Disabled Forced Error Logging as requested... */
2055
2056 #if 0 // (implicit enabling for all devices not currently supported; treat as explicit instead)
2057 if (PSF_ACTION_FEL_IMPLICIT == parm)
2058 {
2059 // Implicit: for ALL devices...
2060 dev->forced_logging = bEnable ? 1 : 0;
2061 }
2062 else // (PSF_ACTION_FEL_EXPLICIT == parm)
2063 #endif // (implicit not supported)
2064 {
2065 // Explicit: for only THIS device...
2066 dev->forced_logging = bEnable ? 1 : 0;
2067 }
2068
2069 build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code);
2070 break;
2071 }
2072
2073 /*-----------------------------------------------------------*/
2074 /* Activate/Deactivate Access Control */
2075 /* 0x8200nn00 / 0x8300nn00 */
2076 /*-----------------------------------------------------------*/
2077 case PSF_ORDER_AAC: // (Activate)
2078 case PSF_ORDER_DAC: // (Dectivate)
2079 {
2080 BYTE bEnable = (PSF_ORDER_AAC == order) ? 1 : 0;
2081
2082 /* Calculate residual byte count */
2083 RESIDUAL_CALC (4);
2084
2085 /* Control information length must be 4 bytes long */
2086 /* and the parameter byte must not be invalid */
2087 if (0
2088 || (count < len)
2089 || (parm & ~(PSF_ACTION_AC_LWP | PSF_ACTION_AC_DCD | // (bits on that shouldn't be)
2090 PSF_ACTION_AC_DCR | PSF_ACTION_AC_ER))
2091 || !(parm & (PSF_ACTION_AC_LWP | PSF_ACTION_AC_DCD | // (bits on that should be)
2092 PSF_ACTION_AC_DCR | PSF_ACTION_AC_ER))
2093 )
2094 {
2095 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
2096 break;
2097 }
2098
2099 /* Enable/Disable Logical Write Protect if requested */
2100 if (parm & PSF_ACTION_AC_LWP)
2101 dev->tdparms.logical_readonly = bEnable ? 1 : 0;
2102
2103 /* Enable/Disable Data Compaction (compression) if requested */
2104 if (parm & PSF_ACTION_AC_DCD)
2105 {
2106 if (TAPEDEVT_HETTAPE == dev->tapedevt)
2107 {
2108 rc = het_cntl( dev->hetb, HETCNTL_SET | HETCNTL_COMPRESS,
2109 bEnable ? TRUE : FALSE );
2110 }
2111 #if defined(OPTION_SCSI_TAPE)
2112 else if (TAPEDEVT_SCSITAPE == dev->tapedevt)
2113 {
2114 // ZZ FIXME: future place for direct SCSI i/o
2115 // to enable/disable compression for 3480/later.
2116 }
2117 #endif
2118 }
2119
2120 build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code);
2121 break;
2122 }
2123
2124 /*-----------------------------------------------------------*/
2125 /* Reset Volume Fenced */
2126 /* 0x9000 */
2127 /*-----------------------------------------------------------*/
2128 case PSF_ORDER_RVF:
2129 {
2130 /* GA32-0127 IBM 3490E Hardware Reference
2131
2132 Volume Fencing
2133
2134 When a condition results in a volume integrity exposure,
2135 the control unit will prevent further access to the volume.
2136 This process is called Volume Fencing and is primarily
2137 related to loss of buffered write data, tape positioning,
2138 or assignment protection.
2139
2140 The control unit prevents further access to the tape volume
2141 by conditioning itself to generate deferred unit checks with
2142 associated sense data indicating ERA code 47, for all commands
2143 that are eligible to receive the deferred unit check until
2144 the condition is reset or until the cartridge is unloaded.
2145 The condition that caused the fencing to occur has already
2146 been indicated by the previous unit check and associated sense
2147 data.
2148 */
2149
2150 /* Calculate residual byte count */
2151 RESIDUAL_CALC (2);
2152
2153 /* Control information length must be 2 bytes long */
2154 if (count < len)
2155 {
2156 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
2157 break;
2158 }
2159
2160 dev->fenced = 0; // (as requested!)
2161
2162 build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code);
2163 break;
2164 }
2165
2166 /*-----------------------------------------------------------*/
2167 /* Pin Device */
2168 /* 0xA100nn */
2169 /*-----------------------------------------------------------*/
2170 case PSF_ORDER_PIN_DEV:
2171 {
2172 /* Calculate residual byte count */
2173 RESIDUAL_CALC (3);
2174
2175 /* Control information length must be 3 bytes long
2176 and the parameter byte must not be invalid */
2177 if ( (count < len)
2178 || ((parm != PSF_ACTION_PIN_CU0) &&
2179 (parm != PSF_ACTION_PIN_CU1))
2180 )
2181 {
2182 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
2183 break;
2184 }
2185
2186 /* Not currently supported; treat as no-op */
2187 build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code);
2188 break;
2189 }
2190
2191 /*-----------------------------------------------------------*/
2192 /* Unpin Device */
2193 /* 0xA200 */
2194 /*-----------------------------------------------------------*/
2195 case PSF_ORDER_UNPIN_DEV:
2196 {
2197 /* Calculate residual byte count */
2198 RESIDUAL_CALC (2);
2199
2200 /* Control information length must be 2 bytes long */
2201 if (count < len)
2202 {
2203 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
2204 break;
2205 }
2206
2207 /* Not currently supported; treat as no-op */
2208 build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code);
2209 break;
2210 }
2211
2212 /*-----------------------------------------------------------*/
2213 /* Prepare for Read Subsystem Data */
2214 /* 0x180000000000mm00iiiiiiii */
2215 /*-----------------------------------------------------------*/
2216 case PSF_ORDER_PRSD:
2217 {
2218 /* GA32-0127 IBM 3490E Hardware Reference
2219
2220 Prepare for Read Subsystem Data (X'18')
2221
2222 The order transfers 12 bytes of data used for processing a
2223 Read Subsystem Data command that immediately follows the
2224 Perform Subsystem Function command specifying this order in
2225 the command chain. If a Read Subsystem Data command is not
2226 issued as the next command in the command chain, the data is
2227 discarded and no other action is performed. If a Read Subsystem
2228 Data command is issued as the next command in the command chain,
2229 the data determines what type of information is presented to
2230 the Read Subsystem Data command.
2231
2232 When the Prepare for Subsystem Data order with the attention
2233 message sub-order is specified in a Perform Subsystem Function
2234 command, the command is treated as a global command. If the
2235 command is issued while the Special Intercept Condition is
2236 active, a unit check status is presented with the associated
2237 sense data indicating ERA code 53.
2238
2239 The Prepare for Read Subsystem Data order requires an order
2240 byte (byte 0), a flag byte (byte 1), and parameter bytes.
2241 The flag byte is set to 0. The parameter bytes are defined
2242 as follows:
2243
2244 ________ ___________________________________________________
2245 | Byte | Description |
2246 |________|___________________________________________________|
2247 | 2-5 | Reserved (X'00') |
2248 |________|___________________________________________________|
2249 | 6 | Attention Message (X'03') |
2250 | | |
2251 | | When active and bytes 8-11 contain X'00000000', |
2252 | | the program is requesting the control unit |
2253 | | to present any pending attention message or |
2254 | | unsolicited unit check condition that is |
2255 | | associated with the addressed device-path pair. |
2256 | | If there is no message or unit check condition |
2257 | | present, the subsystem displays the "No Message" |
2258 | | message. |
2259 | | |
2260 | | When active and bytes 8-11 contain anything |
2261 | | other than X'00000000', the program is re- |
2262 | | questing the control unit to present the status |
2263 | | of the asynchronous operation as identified by |
2264 | | the contents of bytes 8-11. |
2265 |________|___________________________________________________|
2266 | 7 | Reserved (X'00') |
2267 |________|___________________________________________________|
2268 | 8-11 | Message ID |
2269 |________|___________________________________________________|
2270 */
2271
2272 /* Calculate residual byte count */
2273 RESIDUAL_CALC (12);
2274
2275 /* Control information length must be 12 bytes long the */
2276 /* parameter must be valid and all reserved bytes zero. */
2277 /* Also note that the only sub-order we support is the */
2278 /* only sub-order that is defined: attention message. */
2279 if (0
2280 || (count < len)
2281 || (iobuf[6] != PSF_ACTION_SSD_ATNMSG)
2282 || (memcmp( &iobuf[2], "\00\00\00\00", 4 ) != 0)
2283 || (iobuf[7] != 0x00)
2284 )
2285 {
2286 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2287 break;
2288 }
2289
2290 /* If the Special Intercept Condition is active, present
2291 unit check status with sense indicating ERA code 53 */
2292 if (dev->SIC_active)
2293 {
2294 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2295 dev->SIC_active = 0;
2296 break;
2297 }
2298
2299 // Build the requested Subsystem Data...
2300
2301 // PROGRAMMING NOTE: note that we build the requested data
2302 // directly in the channel i/o buffer itself (iobuf). This
2303 // relieves us from having to allocate/maintain a separate
2304 // buffer for it somewhere, and relieves the READ SUBSYSTEM
2305 // DATA command (0x3E) from having to copy the data into
2306 // the channel buffer from somewhere. Instead it can return
2307 // immediately since the data is already in the buffer. (See
2308 // the 0x3E: READ SUBSYSTEM DATA command for information).
2309
2310 // PROGRAMMING NOTE: since at the moment we don't support
2311 // asynchronous i/o (all of our i/o's are synchronous), we
2312 // return either a Format x'00' (No Message) response if the
2313 // Message Id they specified was x'00000000' or, if they
2314 // requested the status for a specific Message Id, a format
2315 // x'02' (Message Id Status) response with x'00' Operation
2316 // Completion Status (I/O Completed).
2317
2318 if (memcmp( &iobuf[8], "\00\00\00\00", 4 ) == 0)
2319 {
2320 /* Format x'00': "No Message" */
2321 dev->tapssdlen = 9; // (Length)
2322 STORE_HW ( &iobuf[0], dev->tapssdlen ); // (Length = 9 bytes)
2323 iobuf[2] = 0x00; // (Format = x'00': "No Message")
2324 iobuf[3] = 0x00; // (Message Code = none)
2325 memcpy( &iobuf[4], &iobuf[8], 4 ); // (Message Id = same as requested)
2326 iobuf[8] = 0x00; // (Flags = none)
2327 }
2328 else
2329 {
2330 /* Format x'02': "Message Id Status" */
2331 dev->tapssdlen = 10; // (Length)
2332 STORE_HW ( &iobuf[0], dev->tapssdlen ); // (Length = 10 bytes)
2333 iobuf[2] = 0x02; // (Format = x'01: Message Id Status)
2334 iobuf[3] = 0x01; // (Message Code = Delayed Response)
2335 memcpy( &iobuf[4], &iobuf[8], 4 ); // (Message Id = same as requested)
2336 iobuf[8] = 0x00; // (Reserved)
2337 iobuf[9] = 0x00; // (Status = "I/O Completed")
2338 }
2339 break;
2340
2341 } /* End case PSF_ORDER_PRSD */
2342
2343 /*-----------------------------------------------------------*/
2344 /* Set Special Intercept Condition */
2345 /* 0x1B00 */
2346 /*-----------------------------------------------------------*/
2347 case PSF_ORDER_SSIC:
2348 {
2349 /* GA32-0127 IBM 3490E Hardware Reference
2350
2351 Set Special Intercept Condition (X'1B')
2352
2353 The order controls the activation or deactivation of the
2354 special intercept condition associated with the device-path
2355 group pair to which the command is issued. The order is
2356 supported by the model if byte 8 bit 4 is active in the data
2357 presented to the Read Device Characteristics command. The
2358 order requires an order byte (byte 0) and a flag byte (byte 1).
2359 The flag byte is set to 0.
2360
2361 When processed, the command activates the special intercept
2362 condition for the device on each channel path that has the
2363 same path group ID as the issuing channel path. The path
2364 group ID is considered valid on a given channel path if it
2365 is valid for any device on the channel path. The special
2366 intercept condition controls the presentation of attention-
2367 intercept status. The sense data associated with the
2368 attention-intercept status indicates ERA code 57. The special
2369 intercept condition also causes the next global command
2370 issued to the device-path group pair to be presented unit check
2371 status with associated sense data indicating ERA code 53.
2372
2373 The special intercept condition is deactivated on a channel
2374 path if a reset signal is received on the channel path. The
2375 special intercept condition is deactivated for the device-group
2376 pair if a global command is presented unit check status with
2377 associated sense data indicating ERA code 53, or if the last
2378 path in the associated set of channel paths (that is, with the
2379 same valid path group ID) is reset.
2380
2381 After the Set Special Intercept Condition order is specified
2382 in a Perform Subsystem Function command, the command is treated
2383 as a global command. If the command is issued while the special
2384 intercept condition is active, a unit check status is presented
2385 with associated sense data indicating ERA code 53.
2386
2387 If a command is issued to a channel path without a valid path
2388 group ID (that is, all devices in the reset state), unit check
2389 status is presented with associated sense data indicating ERA
2390 code 27.
2391 */
2392
2393 /* Command reject if Special Intercept Condition not supported */
2394 if (!dev->SIC_supported) // (not supported?)
2395 {
2396 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2397 break;
2398 }
2399
2400 /* If the command is issued while the Special Intercept */
2401 /* Condition is active, a unit check status is presented */
2402 /* with associated sense data indicating ERA code 53. */
2403 if (dev->SIC_active) // (already active?)
2404 {
2405 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2406 dev->SIC_active = 0; // (reset after UC)
2407 break;
2408 }
2409
2410 /* Activate Special Intercept Condition */
2411 dev->SIC_active = 1;
2412 break;
2413
2414 } /* End case PSF_ORDER_SSIC */
2415
2416 /*-----------------------------------------------------------*/
2417 /* Message Not Supported */
2418 /* 0x1C00xxccnnnn0000iiiiii... */
2419 /*-----------------------------------------------------------*/
2420 case PSF_ORDER_MNS:
2421 {
2422 /* GA32-0127 IBM 3490E Hardware Reference
2423
2424 Message Not Supported (X'1C')
2425
2426 The order transfers 20 bytes of data that identify the host
2427 that does not support a prior attention message containing
2428 the Notify Nonsupport flag. The order requires an order byte
2429 (byte 0), a flag byte (byte 1), and parameter bytes. The
2430 flag byte is set to 0. The parameter bytes are defined as
2431 follows:
2432
2433 ________ ________ ____________________________________________
2434 | Byte | Value | Description |
2435 |________|________|____________________________________________|
2436 | 2 | | Response Code |
2437 |________|________|____________________________________________|
2438 | | 0 | Reserved (invalid). |
2439 |________|________|____________________________________________|
2440 | | 1 | Message rejected. Unknown format. |
2441 |________|________|____________________________________________|
2442 | | 2 | Message rejected. Function not supported. |
2443 |________|________|____________________________________________|
2444 | | 3-255 | Reserved (invalid). |
2445 |________|________|____________________________________________|
2446 | 3 | | Channel Path ID (CHPID) |
2447 | | | |
2448 | | | The byte identifies the channel path that |
2449 | | | received the attention message. |
2450 |________|________|____________________________________________|
2451 | 4, 5 | | Device Number |
2452 | | | |
2453 | | | The bytes identify the device number of |
2454 | | | the device that received the attention |
2455 | | | message. |
2456 |________|________|____________________________________________|
2457 | 6, 7 | | Reserved (must be X'00'). |
2458 |________|________|____________________________________________|
2459 | 8-11 | | Message ID |
2460 | | | |
2461 | | | The field contains the message ID that |
2462 | | | was presented to the host in the attention |
2463 | | | message. |
2464 |________|________|____________________________________________|
2465 | 12-19 | | System ID |
2466 | | | |
2467 | | | The field contains an 8-byte system ID |
2468 | | | that identifies the host or host partition |
2469 | | | responding to the attention message. |
2470 |________|________|____________________________________________|
2471 */
2472
2473 // PROGRAMMING NOTE: none of our responses to the Perform Sub-
2474 // System Function order Attention Message sub-order (see the
2475 // PSF_ORDER_PRSD case further above) support any flags. Thus
2476 // because we never set/request the "Notify Nonsupport" flag
2477 // in our Attention Message sub-order response, the host should
2478 // never actually ever be issuing this particular order of the
2479 // Perform Subsystem Functon command since it shouldn't be
2480 // trying to tell us what we never asked it to. Nevertheless
2481 // we should probably support it anyway just in case it does
2482 // by treating it as a no-op (as long as it's valid of course).
2483
2484 /* Check for valid data (Note: we don't bother validating the
2485 Channel Path ID, Device Number, Message ID or System ID) */
2486 if (0
2487 // || flag != 0x00 // (flag byte) (note: already checked)
2488 || (parm != 0x01 && parm != 0x02) // (response code)
2489 || iobuf[6] != 0x00 // (reserved)
2490 || iobuf[7] != 0x00 // (reserved)
2491 )
2492 {
2493 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2494 break;
2495 }
2496
2497 /* Calculate residual byte count */
2498 RESIDUAL_CALC (20);
2499
2500 /* Treat as No-op */
2501 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
2502 break;
2503
2504 } /* End case PSF_ORDER_MNS */
2505
2506 /*-----------------------------------------------------------*/
2507 /* Unknown/Supported PSF order */
2508 /*-----------------------------------------------------------*/
2509 default:
2510 {
2511 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
2512 break;
2513 }
2514
2515 } /* End PSF switch (order) */
2516
2517 break;
2518
2519 } /* End case 0x77: PERFORM SUBSYSTEM FUNCTION */
2520
2521 /*---------------------------------------------------------------*/
2522 /* DATA SECURITY ERASE */
2523 /*---------------------------------------------------------------*/
2524 case 0x97:
2525 {
2526 /* GA32-0127 IBM 3490E Hardware Reference
2527
2528 Data Security Erase (X'97')
2529
2530 The Data Security Erase command writes a random pattern
2531 from the position of the tape where the command is issued
2532 to the physical end of tape.
2533
2534 The Data Security Erase command must be command-chained
2535 from an Erase Gap command. Most operating systems signal
2536 that the channel program is complete when the channel ending
2537 status is returned for the final command in the chain. If
2538 the Data Security Erase command is the last command in a
2539 channel program, another command should be chained after the
2540 Data Security Erase command. (The No-Operation command is
2541 appropriate.) This practice ensures that any error status
2542 returns with device ending status after the Data Security
2543 Erase command is completed.
2544 */
2545
2546 /* Command reject if not chained from Erase Gap command */
2547 if (!((chained & CCW_FLAGS_CC) && 0x17 == prevcode))
2548 {
2549 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2550 break;
2551 }
2552
2553 /* Command reject if the volume is currently fenced */
2554 if (dev->fenced)
2555 {
2556 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
2557 break;
2558 }
2559
2560 /* Command reject if tape is write-protected */
2561 if (dev->readonly || dev->tdparms.logical_readonly)
2562 {
2563 build_senseX (TAPE_BSENSE_WRITEPROTECT, dev, unitstat, code);
2564 break;
2565 }
2566
2567 /* Update matrix display if needed */
2568 if ( TAPEDISPTYP_IDLE == dev->tapedisptype ||
2569 TAPEDISPTYP_WAITACT == dev->tapedisptype )
2570 {
2571 dev->tapedisptype = TAPEDISPTYP_ERASING;
2572 UpdateDisplay( dev );
2573 }
2574
2575 /* Assign a unique Message Id for this I/O if needed */
2576 INCREMENT_MESSAGEID(dev);
2577
2578 /* Do the DSE; exit if error */
2579 if ((rc = dev->tmh->dse( dev, unitstat, code )) < 0)
2580 break; // (error)
2581
2582 /* Update matrix display if needed */
2583 if ( TAPEDISPTYP_ERASING == dev->tapedisptype )
2584 {
2585 dev->tapedisptype = TAPEDISPTYP_IDLE;
2586 UpdateDisplay( dev );
2587 }
2588
2589 /* Perform flush/sync and/or set normal completion status */
2590 if (0
2591 || !dev->write_immed
2592 || (rc = dev->tmh->sync( dev, unitstat, code )) == 0
2593 )
2594 build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code );
2595
2596 break;
2597
2598 } /* End case 0x97: DATA SECURITY ERASE */
2599
2600 /*---------------------------------------------------------------*/
2601 /* LOAD DISPLAY */
2602 /*---------------------------------------------------------------*/
2603 case 0x9F:
2604 {
2605 /* Command Reject if Supervisor-Inhibit */
2606 if (dev->supvr_inhibit)
2607 {
2608 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2609 break;
2610 }
2611
2612 /* Calculate residual byte count */
2613 RESIDUAL_CALC (17);
2614
2615 /* Issue message on 3480 matrix display */
2616 load_display (dev, iobuf, count);
2617
2618 /* Return unit status */
2619 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
2620 break;
2621 }
2622
2623 /*---------------------------------------------------------------*/
2624 /* Read and Reset Buffered Log (9347) */
2625 /*---------------------------------------------------------------*/
2626 case 0xA4:
2627 {
2628 /* Calculate residual byte count */
2629 RESIDUAL_CALC (dev->numsense);
2630
2631 /* Reset SENSE Data */
2632 memset (dev->sense, 0, sizeof(dev->sense));
2633 *unitstat = CSW_CE|CSW_DE;
2634
2635 /* Copy device Buffered log data (Bunch of 0s for now) */
2636 memcpy (iobuf, dev->sense, num);
2637
2638 /* Indicate Contengency Allegiance has been cleared */
2639 dev->sns_pending = 0;
2640 break;
2641 }
2642
2643 /*---------------------------------------------------------------*/
2644 /* SET PATH GROUP ID */
2645 /*---------------------------------------------------------------*/
2646 case 0xAF:
2647 {
2648 /* GA32-0127 IBM 3490E Hardware Reference
2649
2650 Set Path Group ID (X'AF')
2651
2652 The Set Path Group ID command identifies a controlling computer
2653 and specific channel path to the addressed control unit and
2654 tape drive.
2655
2656 The Set Path Group ID command transfers 12 bytes of path group
2657 ID information to the subsystem. The first byte (byte 0) is a
2658 function control byte, and the remaining 11 bytes (bytes 1-11)
2659 contain the path-group ID.
2660
2661 The bit assignments in the function control byte (byte 0) are:
2662
2663 ________ ________ ___________________________________________
2664 | Bit | Value | Description |
2665 |________|________|___________________________________________|
2666 | 0 | | Path Mode |
2667 |________|________|___________________________________________|
2668 | | 0 | Single-path Mode |
2669 |________|________|___________________________________________|
2670 | | 1 | Multipath Mode (not supported by Models |
2671 | | | C10, C11, and C22) |
2672 |________|________|___________________________________________|
2673 | 1, 2 | | Group Code |
2674 |________|________|___________________________________________|
2675 | | 00 | Establish Group |
2676 |________|________|___________________________________________|
2677 | | 01 | Disband Group |
2678 |________|________|___________________________________________|
2679 | | 10 | Resign from Group |
2680 |________|________|___________________________________________|
2681 | | 11 | Reserved |
2682 |________|________|___________________________________________|
2683 | 3-7 | 00000 | Reserved |
2684 |________|________|___________________________________________|
2685
2686
2687 The final 11 bytes of the Set Path Group ID command identify
2688 the path group ID. The path group ID identifies the channel
2689 paths that belong to the same controlling computer. Path group
2690 ID bytes must be the same for all devices in a control unit
2691 on a given path. The Path Group ID bytes cannot be all zeroes.
2692 */
2693
2694 /* Command Reject if Supervisor-Inhibit */
2695 if (dev->supvr_inhibit)
2696 {
2697 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2698 break;
2699 }
2700
2701 /* Command reject if the command is not the ONLY command
2702 in the channel program */
2703 if (chained & CCW_FLAGS_CC)
2704 {
2705 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2706 break;
2707 }
2708
2709 /* Calculate residual byte count */
2710 RESIDUAL_CALC (12);
2711
2712 /* Control information length must be at least 12 bytes */
2713 if (count < 12)
2714 {
2715 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2716 break;
2717 }
2718
2719 /* Byte 0 is the path group state byte */
2720 switch((iobuf[0] & SPG_SET_COMMAND))
2721 {
2722 case SPG_SET_ESTABLISH:
2723 /* Only accept the new pathgroup id when
2724 1) it has not yet been set (ie contains zeros) or
2725 2) It is set, but we are setting the same value */
2726 if(memcmp(dev->pgid,
2727 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 11)
2728 && memcmp(dev->pgid, iobuf+1, 11))
2729 {
2730 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2731 break;
2732 }
2733
2734 /* Bytes 1-11 contain the path group identifier */
2735 memcpy (dev->pgid, iobuf+1, 11); // (set initial value)
2736 dev->pgstat = SPG_PATHSTAT_GROUPED | SPG_PARTSTAT_IENABLED;
2737 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
2738 break;
2739
2740 case SPG_SET_DISBAND:
2741 dev->pgstat = 0;
2742 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
2743 break;
2744
2745 default:
2746 case SPG_SET_RESIGN:
2747 dev->pgstat = 0;
2748 memset (dev->pgid, 0, 11); // (reset to zero)
2749 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
2750 break;
2751
2752 } // end switch((iobuf[0] & SPG_SET_COMMAND))
2753
2754 break;
2755
2756 } /* End case 0xAF: SET PATH GROUP ID */
2757
2758 /*---------------------------------------------------------------*/
2759 /* ASSIGN */
2760 /*---------------------------------------------------------------*/
2761 case 0xB7:
2762 {
2763 /* Command Reject if Supervisor-Inhibit */
2764 if (dev->supvr_inhibit)
2765 {
2766 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2767 break;
2768 }
2769
2770 /* Calculate residual byte count */
2771 RESIDUAL_CALC (11);
2772
2773 /* Control information length must be at least 11 bytes */
2774 if (count < len)
2775 {
2776 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2777 break;
2778 }
2779
2780 if((memcmp(iobuf,"\00\00\00\00\00\00\00\00\00\00",11)==0)
2781 || (memcmp(iobuf,dev->pgid,11)==0))
2782 {
2783 dev->pgstat |= SPG_PARTSTAT_XENABLED; /* Set Explicit Partition Enabled */
2784 }
2785 else
2786 {
2787 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2788 break;
2789 }
2790
2791 /* Return unit status */
2792 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
2793 break;
2794 }
2795
2796 /*---------------------------------------------------------------*/
2797 /* MEDIUM SENSE (3590) */
2798 /*---------------------------------------------------------------*/
2799 case 0xC2:
2800 {
2801 /* GA32-0331 IBM 3590 Hardware Reference
2802
2803 The 3590 Hardware Reference manual lists many different
2804 "Mode Sense" Pages that the 3590 supports, with one of
2805 the supported pages being Mode Page X'23': the "Medium
2806 Sense" mode page:
2807
2808 The Medium Sense page provides information about
2809 the state of the medium currently associated with
2810 the device, if any.
2811 */
2812
2813 #if 0 // ZZ FIXME: not coded yet
2814
2815 // PROGRAMMING NOTE: until we can add support to Hercules
2816 // allowing direct SCSI i/o (so that we can issue the 10-byte
2817 // Mode Sense (X'5A') command to ask for Mode Page x'23' =
2818 // Medium Sense) we have no choice but to reject the command.
2819
2820 // ZZ FIXME: not written yet.
2821
2822 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2823
2824 #else // ++++ BEGIN MEDIUM SENSE HACK ++++
2825
2826 /* ZZ FIXME: *** TEMPORARY(?) HACK ***
2827
2828 The following clues were gleaned from Linux 390 source:
2829
2830 struct tape_3590_med_sense
2831 {
2832 unsigned int macst:4;
2833 unsigned int masst:4;
2834
2835 char pad[127];
2836 }
2837
2838 #define MSENSE_UNASSOCIATED 0x00
2839 #define MSENSE_ASSOCIATED_MOUNT 0x01
2840 #define MSENSE_ASSOCIATED_UMOUNT 0x02
2841
2842 case TO_MSEN:
2843
2844 sense = (struct tape_3590_med_sense *) request->cpdata;
2845
2846 if (sense->masst == MSENSE_UNASSOCIATED)
2847 tape_med_state_set(device, MS_UNLOADED);
2848
2849 if (sense->masst == MSENSE_ASSOCIATED_MOUNT)
2850 tape_med_state_set(device, MS_LOADED);
2851 break;
2852 */
2853
2854 /* Calculate residual byte count */
2855 RESIDUAL_CALC (128);
2856
2857 /* Return Media Sense data... */
2858
2859 memset( iobuf, 0, num ); // (init to all zeroes first)
2860
2861 if (dev->tmh->tapeloaded( dev, unitstat, code ))
2862 iobuf[0] |= (0x01 & 0x0F); // MSENSE_ASSOCIATED_MOUNT
2863 // else
2864 // iobuf[0] |= (0x00 & 0x0F); // MSENSE_UNASSOCIATED
2865
2866 /* Return unit status */
2867 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
2868
2869 #endif // ++++ END MEDIUM SENSE HACK ++++
2870
2871 break;
2872
2873 } /* End case 0xC2: MEDIUM SENSE */
2874
2875 /*---------------------------------------------------------------*/
2876 /* SET TAPE-WRITE IMMEDIATE (3480 and later) */
2877 /*---------------------------------------------------------------*/
2878 case 0xC3:
2879 {
2880 // NOTE: the "Mode Set" interpretation of this CCW for all
2881 // models earlier than 3480 are handled by the command-table;
2882 // the "Set Tape-Write Immediate" interpretation of this CCW
2883 // for 3480 and later models is handled below.
2884
2885 /* Command reject if the volume is currently fenced */
2886 if (dev->fenced)
2887 {
2888 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
2889 break;
2890 }
2891
2892 /* GA32-0127 IBM 3490E Hardware Reference
2893
2894 Set Tape-Write-Immediate (X'C3')
2895
2896 The Set Tape-Write-Immediate command causes all subsequent
2897 Write commands in the channel program to perform as write-
2898 immediate commands.
2899
2900 The tape-write-immediate command is explicitly requested by a
2901 Mode Set or Set Tape-Write-Immediate command. The subsystem
2902 forces the tape-write-immediate command while the tape is
2903 positioned beyond logical end of volume. This prevents more
2904 than one record from being in the buffer if the physical end of
2905 volume is reached. It may also be forced when load balancing
2906 is performed or on drives that write the 3480-2 XF format just
2907 before end of wrap processing.
2908 */
2909
2910 /* GA32-0329 3590 Introduction and Planning Guide
2911
2912 When data is physically transferred to the tape medium it is
2913 always immediately reread and verified. The writing of data
2914 is normally buffered, however, which defers the physical
2915 transfer of the logical blocks to the tape until the buffer
2916 conditions require the offloading of the data or until a
2917 synchronizing command requires the transfer. If immediate
2918 validation of a successful transfer of data to the tape is
2919 required at the time that each logical block is written,
2920 then Tape Write Immediate mode may be programmatically invoked.
2921 This results in block-by-block synchronization and verification
2922 of successful transfer all the way to the medium, but at a
2923 very substantial cost in application performance.
2924 */
2925
2926 /* Assign a unique Message Id for this I/O if needed */
2927 INCREMENT_MESSAGEID(dev);
2928
2929 /* set write-immedediate mode and perform sync function */
2930 dev->write_immed = 1;
2931 if ((rc = dev->tmh->sync( dev, unitstat, code )) == 0)
2932 build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code );
2933 break;
2934
2935 } /* End case 0xC3: SET TAPE-WRITE IMMEDIATE */
2936
2937 /*---------------------------------------------------------------*/
2938 /* UNASSIGN */
2939 /*---------------------------------------------------------------*/
2940 case 0xC7:
2941 {
2942 /* Command Reject if Supervisor-Inhibit */
2943 if (dev->supvr_inhibit)
2944 {
2945 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2946 break;
2947 }
2948
2949 /* Calculate residual byte count */
2950 RESIDUAL_CALC (11);
2951
2952 /* Control information length must be at least 11 bytes */
2953 if (count < len)
2954 {
2955 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2956 break;
2957 }
2958
2959 /* Reset to All Implicitly enabled */
2960 dev->pgstat=0;
2961
2962 /* Reset Path group ID password */
2963 memset(dev->pgid,0,11);
2964
2965 /* Reset drive password */
2966 memset(dev->drvpwd,0,sizeof(dev->drvpwd));
2967
2968 /* Return unit status */
2969 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
2970 break;
2971 }
2972
2973 /*---------------------------------------------------------------*/
2974 /* MODE SENSE (3590) */
2975 /*---------------------------------------------------------------*/
2976 case 0xCF:
2977 {
2978 /* ANSI INCITS 131-1994 (R1999) SCSI-2 Reference
2979
2980 The MODE SENSE command provides a means for a target to
2981 report parameters to the initiator. It is a complementary
2982 command to the MODE SELECT command.
2983 */
2984
2985 /* GA32-0331 IBM 3590 Hardware Reference
2986
2987 The 3590 Hardware Reference manual lists many different
2988 "Mode Sense" Pages that the 3590 supports.
2989 */
2990
2991 // ZZ FIXME: not written yet.
2992
2993 /* Set command reject sense byte, and unit check status */
2994 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
2995 break;
2996 }
2997
2998 /*---------------------------------------------------------------*/
2999 /* MODE SET (3480 or later) */
3000 /*---------------------------------------------------------------*/
3001 case 0xDB:
3002 {
3003 /* GA32-0127 IBM 3490E Hardware Reference
3004
3005 Mode Set (X'DB')
3006
3007 The Mode Set command controls specific aspects of command
3008 processing within a given command chain.
3009
3010 The Mode Set command requires one byte of information from the channel.
3011 The format of the byte is:
3012
3013 ________ __________________________________________________________
3014 | Bit | Description |
3015 |________|__________________________________________________________|
3016 | 0,1 | Reserved |
3017 |________|__________________________________________________________|
3018 | 2 | Tape-Write-Immediate Mode |
3019 | | |
3020 | | If active, any subsequent Write commands within the |
3021 | | current command chain are processed in tape-write- |
3022 | | immediate mode if no other conditions preclude this |
3023 | | mode. If inactive, Write commands are processed in |
3024 | | buffered mode if no other conditions preclude this |
3025 | | mode. The default is inactivate. |
3026 |________|__________________________________________________________|
3027 | 3 | Supervisor Inhibit |
3028 | | |
3029 | | If active, any subsequent supervisor command within |
3030 | | the current command chain is presented unit check |
3031 | | status with associated sense data indicating ERA code |
3032 | | 27. The supervisor inhibit control also determines |
3033 | | if pending buffered log data is reset when a Read |
3034 | | Buffered Log command is issued. The default is |
3035 | | inactivate. |
3036 |________|__________________________________________________________|
3037 | 4 | Improved Data Recording Capability (IDRC) |
3038 | | |
3039 | | If active, IDRC is invoked for any subsequent Write |
3040 | | commands within the current command chain. See Table |
3041 | | 7 in topic 1.16.6 for the default settings. |
3042 |________|__________________________________________________________|
3043 | 5-7 | Reserved |
3044 |________|__________________________________________________________|
3045
3046 The Mode Set command is a supervisor command and cannot be performed
3047 if preceded by a Mode Set command that inhibits supervisor commands.
3048 */
3049
3050 /* Command reject if the volume is currently fenced */
3051 if (dev->fenced)
3052 {
3053 build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code);
3054 break;
3055 }
3056
3057 /* Calculate residual byte count */
3058 RESIDUAL_CALC (1);
3059
3060 /* Check for count field of at least 1 byte, and that
3061 supvr-inhibit mode hasn't already been established */
3062 if (0
3063 || count < len
3064 || dev->supvr_inhibit
3065 )
3066 {
3067 build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code);
3068 break;
3069 }
3070
3071 /* Assign a unique Message Id for this I/O if needed */
3072 INCREMENT_MESSAGEID(dev);
3073
3074 /* Process request */
3075 if (iobuf[0] & MSET_SUPVR_INHIBIT)
3076 dev->supvr_inhibit = 1; /* set supvr-inhibit mode*/
3077
3078 if (iobuf[0] & MSET_WRITE_IMMED)
3079 dev->write_immed = 1; /* set write-immed. mode */
3080
3081 build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code);
3082 break;
3083
3084 } /* End case 0xDB: MODE SET */
3085
3086 /*---------------------------------------------------------------*/
3087 /* CONTROL ACCESS */
3088 /*---------------------------------------------------------------*/
3089 case 0xE3:
3090 {
3091 /* GA32-0127 IBM 3490E Hardware Reference
3092
3093 Control Access (X'E3')
3094
3095 The Control Access command is used to perform the set-password,
3096 conditional-enable, and conditional-disable functions of dynamic
3097 partitioning.
3098
3099 The command requires 12 bytes of data to be transferred from the
3100 channel to the control unit which is defined as follows:
3101
3102 ________ ________ ___________________________________________
3103 | Byte | Bit | Description |
3104 |________|________|___________________________________________|
3105 | 0 | | Function Control |
3106 |________|________|___________________________________________|
3107 | | 0,1 | 0 (x'00') Set Password |
3108 | | | 1 (x'40') Conditional Disable |
3109 | | | 2 (x'80') Conditional Enable |
3110 | | | 3 (x'C0') Reserved (Invalid) |
3111 |________|________|___________________________________________|
3112 | | 2-7 | Reserved (must be B'0') |
3113 |________|________|___________________________________________|
3114 | 1-11 | | Password |
3115 |________|________|___________________________________________|
3116 */
3117
3118 /* Command Reject if Supervisor-Inhibit */
3119 if (dev->supvr_inhibit)
3120 {
3121 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
3122 break;
3123 }
3124
3125 /* Calculate residual byte count */
3126 RESIDUAL_CALC (12);
3127
3128 /* Control information length must be at least 12 bytes */
3129 if (count < len)
3130 {
3131 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
3132 break;
3133 }
3134
3135 /* Byte 0 is the CAC mode-of-use */
3136 switch (iobuf[0])
3137 {
3138 /*-----------------------------------------------------------*/
3139 /* Set Password */
3140 /* 0x00nnnnnnnnnnnnnnnnnnnnnn */
3141 /*-----------------------------------------------------------*/
3142 case CAC_SET_PASSWORD:
3143 {
3144 /* Password must not be zero
3145 and the device path must be Explicitly Enabled */
3146 if (0
3147 || memcmp( iobuf+1, "\00\00\00\00\00\00\00\00\00\00\00", 11 ) == 0
3148 || (dev->pgstat & SPG_PARTSTAT_XENABLED) == 0
3149 )
3150 {
3151 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
3152 break;
3153 }
3154
3155 /* Set Password if none set yet */
3156 if (memcmp( dev->drvpwd, "\00\00\00\00\00\00\00\00\00\00\00", 11 ) == 0)
3157 {
3158 memcpy (dev->drvpwd, iobuf+1, 11);
3159 }
3160 else /* Password already set - they must match */
3161 {
3162 if (memcmp( dev->drvpwd, iobuf+1, 11 ) != 0)
3163 {
3164 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
3165 break;
3166 }
3167 }
3168 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
3169 break;
3170 }
3171
3172 /*-----------------------------------------------------------*/
3173 /* Conditional Enable */
3174 /* 0x80nnnnnnnnnnnnnnnnnnnnnn */
3175 /*-----------------------------------------------------------*/
3176 case CAC_COND_ENABLE:
3177 {
3178 /* A drive password must be set and it must match the one given as input */
3179 if (0
3180 || memcmp( dev->drvpwd, "\00\00\00\00\00\00\00\00\00\00\00", 11 ) == 0
3181 || memcmp( dev->drvpwd, iobuf+1, 11 ) != 0
3182 )
3183 {
3184 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
3185 break;
3186 }
3187 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
3188 break;
3189 }
3190
3191 /*-----------------------------------------------------------*/
3192 /* Conditional Disable */
3193 /* 0x40nnnnnnnnnnnnnnnnnnnnnn */
3194 /*-----------------------------------------------------------*/
3195 case CAC_COND_DISABLE:
3196 {
3197 /* A drive password is set, it must match the one given as input */
3198 if (1
3199 && memcmp (dev->drvpwd, "\00\00\00\00\00\00\00\00\00\00\00", 11) != 0
3200 && memcmp (dev->drvpwd, iobuf+1, 11) != 0
3201 )
3202 {
3203 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
3204 break;
3205 }
3206
3207 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
3208 break;
3209 }
3210
3211 default: /* Unsupported Control Access Function */
3212 {
3213 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
3214 break;
3215 }
3216
3217 } /* End switch (iobuf[0]) */
3218
3219 break;
3220
3221 } /* End case 0xE3 CONTROL ACCESS */
3222
3223 /*---------------------------------------------------------------*/
3224 /* SENSE ID (3422 and later) */
3225 /*---------------------------------------------------------------*/
3226 case 0xE4:
3227 {
3228 #if defined( OPTION_TAPE_AUTOMOUNT )
3229 /* AUTOMOUNT QUERY - part 2 (if command-chained from prior 0x4B) */
3230 if (1
3231 && dev->tapedevt != TAPEDEVT_SCSITAPE
3232 && sysblk.tamdir != NULL
3233 && !dev->noautomount
3234 && (chained & CCW_FLAGS_CC)
3235 && 0x4B == prevcode
3236 )
3237 {
3238 int i; // (work)
3239
3240 /* Calculate residual byte count */
3241 RESIDUAL_CALC (strlen(dev->filename));
3242
3243 /* Copy device filename to guest storage */
3244 for (i=0; i < num; i++)
3245 iobuf[i] = host_to_guest( dev->filename[i] );
3246
3247 /* Return normal status */
3248 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
3249 break;
3250 }
3251 #endif /* OPTION_TAPE_AUTOMOUNT */
3252
3253 /* SENSE ID did not exist on the 3803 */
3254 /* If numdevid is 0, then 0xE4 not supported */
3255 if (dev->numdevid==0)
3256 {
3257 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
3258 break;
3259 }
3260
3261 /* Calculate residual byte count */
3262 RESIDUAL_CALC (dev->numdevid);
3263
3264 /* Copy device identifier bytes to channel I/O buffer */
3265 memcpy (iobuf, dev->devid, num);
3266
3267 /* Return unit status */
3268 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
3269 break;
3270 }
3271
3272 /*---------------------------------------------------------------*/
3273 /* READ CONFIGURATION DATA (3490 and later) */
3274 /*---------------------------------------------------------------*/
3275 case 0xFA:
3276 {
3277 /* GA32-0127 IBM 3490E Hardware Reference
3278
3279 Read Configuration Data (X'FA')
3280
3281 A Read Configuration Data command causes 160 bytes of data to
3282 be transferred from the control unit to the channel. The data
3283 transferred by this command is referred to as a configuration
3284 record and is associated with the addressed device-path pair.
3285 The configuration record from each device-path pair provides the
3286 host with identifiers of node elements internal to the subsystem.
3287 */
3288
3289 static const BYTE cfgdata[] = // (prototype data)
3290 {
3291 // ---------------- Device NED ---------------------------------------------------
3292 0xCC, // 0: NED code
3293 0x01, // 1: Type (X'01' = I/O Device)
3294 0x02, // 2: Class (X'02' = Magnetic Tape)
3295 0x00, // 3: (Reserved)
3296 0xF0,0xF0,0xF3,0xF4,0xF9,0xF0, // 4-9: Type ('003490')
3297 0xC3,0xF1,0xF0, // 10-12: Model ('C10')
3298 0xC8,0xD9,0xC3, // 13-15: Manufacturer ('HRC' = Hercules)
3299 0xE9,0xE9, // 16-17: Plant of Manufacture ('ZZ' = Herc)
3300 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // 18-29: Sequence Number
3301 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, //
3302 0x00, 0x00, // 30-31: Tag (x'000n', n = Logical Drive Address)
3303 // ---------------- Control Unit NED ---------------------------------------------
3304 0xC4, // 32: NED code
3305 0x02, // 33: Type (X'02' = Control Unit)
3306 0x00, // 34: Class (X'00' = Undefined)
3307 0x00, // 35: (Reserved)
3308 0xF0,0xF0,0xF3,0xF4,0xF9,0xF0, // 36-41: Type ('003490')
3309 0xC3,0xF1,0xF0, // 42-44: Model ('C10')
3310 0xC8,0xD9,0xC3, // 45-47: Manufacturer ('HRC' = Hercules)
3311 0xE9,0xE9, // 48-49: Plant of Manufacture ('ZZ' = Herc)
3312 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // 50-61: Sequence Number
3313 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, //
3314 0x00, 0x00, // 62-63: Tag (x'0000')
3315 // ---------------- Library NED --------------------------------------------------
3316 0x00, // 64: NED code (x'00' = Not Used)
3317 0x00, // 65: Type
3318 0x00, // 66: Class
3319 0x00, // 67: (Reserved)
3320 0x00,0x00,0x00,0x00,0x00,0x00, // 68-73: Type
3321 0x00,0x00,0x00, // 74-76: Model
3322 0x00,0x00,0x00, // 77-79: Manufacturer
3323 0x00,0x00, // 80-81: Plant of Manufacture
3324 0x00,0x00,0x00,0x00,0x00,0x00, // 82-93: Sequence Number
3325 0x00,0x00,0x00,0x00,0x00,0x00, //
3326 0x00, 0x00, // 94-95: Tag
3327 // ---------------- Token NED ---------------------------------------------------
3328 0xEC, // 96: NED code
3329 0x00, // 97: Type (X'00' = Unspecified)
3330 0x00, // 98: Class (X'00' = Undefined)
3331 0x00, // 99: (Reserved)
3332 0xF0,0xF0,0xF3,0xF4,0xF9,0xF0, // 100-105: Type ('003490')
3333 0xC3,0xF1,0xF0, // 106-108: Model ('C10')
3334 0xC8,0xD9,0xC3, // 109-111: Manufacturer ('HRC' = Hercules)
3335 0xE9,0xE9, // 112-113: Plant of Manufacture ('ZZ' = Herc)
3336 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // 114-125: Sequence Number
3337 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, //
3338 0x00, 0x00, // 126-127: Tag (x'0000')
3339 // ---------------- General NEQ --------------------------------------------------
3340 0x80, // 128: NED code
3341 0x80, // 129: Record Selector:
3342 // x'80' = Control Unit 0
3343 // x'81' = Control Unit 1
3344 0x00,0x80, // 130-131: Interface Id:
3345 // x'0080' = CU Channel Adapter A
3346 // x'0040' = CU Channel Adapter B
3347 0x00, // 132: Device-Dependent Timeout
3348 0x00,0x00,0x00, // 133-135: (Reserved)
3349 0x00, // 136: Extended Information:
3350 // x'00' for Logical Drive Addresses 0-7
3351 // x'01' for Logical Drive Addresses 8-F
3352 0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 137-159: (Reserved)
3353 0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3354 0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3355 0x00,0x00,
3356 };
3357
3358 ASSERT( sizeof(cfgdata) == 160 );
3359
3360 /* Calculate residual byte count */
3361 RESIDUAL_CALC (160);
3362
3363 /* Copy prototype Configuration Data to channel I/O buffer */
3364 memcpy (iobuf, cfgdata, sizeof(cfgdata));
3365
3366 /* Fixup values for this particular device/type... NOTE: we
3367 only fixup the Device and Control Unit NEDs here. The Token
3368 NED's type/model values come from the Device NED's values.
3369 */
3370 if (0x3480 == dev->devtype)
3371 {
3372 memcpy (&iobuf[7], "\xF4\xF8", 2); // '48'
3373 memcpy (&iobuf[39], "\xF4\xF8", 2); // '48'
3374
3375 memcpy (&iobuf[10], "\xC4\xF3\xF1", 3); // 'D31'
3376 memcpy (&iobuf[42], "\xC4\xF3\xF1", 3); // 'D31'
3377 }
3378 else if (0x3490 == dev->devtype)
3379 {
3380 // memcpy (&iobuf[7], "\xF4\xF9", 2); // '49'
3381 // memcpy (&iobuf[39], "\xF4\xF9", 2); // '49'
3382
3383 // memcpy (&iobuf[10], "\xC3\xF1\xF0", 3); // 'C10'
3384 // memcpy (&iobuf[42], "\xC3\xF1\xF0", 3); // 'C10'
3385 }
3386 else if (0x3590 == dev->devtype)
3387 {
3388 memcpy (&iobuf[7], "\xF5\xF9", 2); // '59'
3389 memcpy (&iobuf[39], "\xF5\xF9", 2); // '59'
3390
3391 memcpy (&iobuf[10], "\xC2\xF1\xC1", 3); // 'B1A'
3392 memcpy (&iobuf[42], "\xC1\xF5\xF0", 3); // 'A50'
3393 }
3394
3395 memcpy (&iobuf[100], &iobuf[4], 9); // (set Token NED Type/Model from Device NED)
3396
3397 iobuf[31] |= (dev->devnum & 0x0F); // (set Logical Drive Address)
3398
3399 if ((dev->devnum & 0x0F) > 7)
3400 iobuf[136] = 0x01; // (set Extended Information)
3401
3402 /* Return normal status */
3403 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code);
3404 break;
3405
3406 } /* End case 0xFA: READ CONFIGURATION DATA */
3407
3408 /*---------------------------------------------------------------*/
3409 /* INVALID OPERATION */
3410 /*---------------------------------------------------------------*/
3411 default:
3412 {
3413 /* Set command reject sense byte, and unit check status */
3414 build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code);
3415 }
3416
3417 } /* end switch (code) */
3418
3419 } /* end function tapedev_execute_ccw */
3420
3421 #if defined( OPTION_TAPE_AUTOMOUNT )
3422 /*-------------------------------------------------------------------*/
3423 /* Find next more-restrictive TAMDIR subdirectory entry... */
3424 /*-------------------------------------------------------------------*/
findtamdir(int rej,int minlen,const char * pszDir)3425 static TAMDIR* findtamdir( int rej, int minlen, const char* pszDir )
3426 {
3427 TAMDIR *pTAMDIR = sysblk.tamdir; /* always search entire list */
3428 do
3429 if (1
3430 && pTAMDIR->rej == rej
3431 && pTAMDIR->len > minlen
3432 && strnfilenamecmp( pszDir, pTAMDIR->dir, pTAMDIR->len ) == 0
3433 )
3434 return pTAMDIR;
3435 while ((pTAMDIR = pTAMDIR->next) != NULL);
3436 return NULL;
3437 }
3438 #endif // defined( OPTION_TAPE_AUTOMOUNT )
3439
3440 /*-------------------------------------------------------------------*/
3441 /* Load Display channel command processing... */
3442 /*-------------------------------------------------------------------*/
load_display(DEVBLK * dev,BYTE * buf,U16 count)3443 void load_display (DEVBLK *dev, BYTE *buf, U16 count)
3444 {
3445 U16 i; /* Array subscript */
3446 char msg1[9], msg2[9]; /* Message areas (ASCIIZ) */
3447 BYTE fcb; /* Format Control Byte */
3448 BYTE tapeloaded; /* (boolean true/false) */
3449 BYTE* msg; /* (work buf ptr) */
3450
3451 if ( !count )
3452 return;
3453
3454 /* Pick up format control byte */
3455 fcb = *buf;
3456
3457 /* Copy and translate messages... */
3458
3459 memset( msg1, 0, sizeof(msg1) );
3460 memset( msg2, 0, sizeof(msg2) );
3461
3462 msg = buf+1;
3463
3464 for (i=0; *msg && i < 8 && ((i+1)+0) < count; i++)
3465 msg1[i] = guest_to_host(*msg++);
3466
3467 msg = buf+1+8;
3468
3469 for (i=0; *msg && i < 8 && ((i+1)+8) < count; i++)
3470 msg2[i] = guest_to_host(*msg++);
3471
3472 msg1[ sizeof(msg1) - 1 ] = 0;
3473 msg2[ sizeof(msg2) - 1 ] = 0;
3474
3475 tapeloaded = dev->tmh->tapeloaded( dev, NULL, 0 );
3476
3477 switch ( fcb & FCB_FS ) // (high-order 3 bits)
3478 {
3479 case FCB_FS_READYGO: // 0x00
3480
3481 /*
3482 || 000b: "The message specified in bytes 1-8 and 9-16 is
3483 || maintained until the tape drive next starts tape
3484 || motion, or until the message is updated."
3485 */
3486
3487 dev->tapedispflags = 0;
3488
3489 strlcpy( dev->tapemsg1, msg1, sizeof(dev->tapemsg1) );
3490 strlcpy( dev->tapemsg2, msg2, sizeof(dev->tapemsg2) );
3491
3492 dev->tapedisptype = TAPEDISPTYP_WAITACT;
3493
3494 break;
3495
3496 case FCB_FS_UNMOUNT: // 0x20
3497
3498 /*
3499 || 001b: "The message specified in bytes 1-8 is maintained
3500 || until the tape cartridge is physically removed from
3501 || the tape drive, or until the next unload/load cycle.
3502 || If the drive does not contain a cartridge when the
3503 || Load Display command is received, the display will
3504 || contain the message that existed prior to the receipt
3505 || of the command."
3506 */
3507
3508 dev->tapedispflags = 0;
3509
3510 if ( tapeloaded )
3511 {
3512 dev->tapedisptype = TAPEDISPTYP_UNMOUNT;
3513 dev->tapedispflags = TAPEDISPFLG_REQAUTOMNT;
3514
3515 strlcpy( dev->tapemsg1, msg1, sizeof(dev->tapemsg1) );
3516
3517 if ( dev->ccwtrace || dev->ccwstep )
3518 logmsg(_("HHCTA099I %4.4X: Tape Display \"%s\" Until Unmounted\n"),
3519 dev->devnum, dev->tapemsg1 );
3520 }
3521
3522 break;
3523
3524 case FCB_FS_MOUNT: // 0x40
3525
3526 /*
3527 || 010b: "The message specified in bytes 1-8 is maintained
3528 || until the drive is next loaded. If the drive is
3529 || loaded when the Load Display command is received,
3530 || the display will contain the message that existed
3531 || prior to the receipt of the command."
3532 */
3533
3534 dev->tapedispflags = 0;
3535
3536 if ( !tapeloaded )
3537 {
3538 dev->tapedisptype = TAPEDISPTYP_MOUNT;
3539 dev->tapedispflags = TAPEDISPFLG_REQAUTOMNT;
3540
3541 strlcpy( dev->tapemsg1, msg1, sizeof(dev->tapemsg1) );
3542
3543 if ( dev->ccwtrace || dev->ccwstep )
3544 logmsg(_("HHCTA099I %4.4X: Tape Display \"%s\" Until Mounted\n"),
3545 dev->devnum, dev->tapemsg1 );
3546 }
3547
3548 break;
3549
3550 case FCB_FS_NOP: // 0x60
3551 default:
3552
3553 /*
3554 || 011b: "This value is used to physically access a drive
3555 || without changing the message display. This option
3556 || can be used to test whether a control unit can
3557 || physically communicate with a drive."
3558 */
3559
3560 return;
3561
3562 case FCB_FS_RESET_DISPLAY: // 0x80
3563
3564 /*
3565 || 100b: "The host message being displayed is cancelled and
3566 || a unit message is displayed instead."
3567 */
3568
3569 dev->tapedispflags = 0;
3570 dev->tapedisptype = TAPEDISPTYP_IDLE;
3571
3572 break;
3573
3574 case FCB_FS_UMOUNTMOUNT: // 0xE0
3575
3576 /*
3577 || 111b: "The message in bytes 1-8 is displayed until a tape
3578 || cartridge is physically removed from the tape drive,
3579 || or until the drive is next loaded. The message in
3580 || bytes 9-16 is displayed until the drive is next loaded.
3581 || If no cartridge is present in the drive, the first
3582 || message is ignored and only the second message is
3583 || displayed until the drive is next loaded."
3584 */
3585
3586 dev->tapedispflags = 0;
3587
3588 strlcpy( dev->tapemsg1, msg1, sizeof(dev->tapemsg1) );
3589 strlcpy( dev->tapemsg2, msg2, sizeof(dev->tapemsg2) );
3590
3591 if ( tapeloaded )
3592 {
3593 dev->tapedisptype = TAPEDISPTYP_UMOUNTMOUNT;
3594 dev->tapedispflags = TAPEDISPFLG_REQAUTOMNT;
3595
3596 if ( dev->ccwtrace || dev->ccwstep )
3597 logmsg(_("HHCTA099I %4.4X: Tape Display \"%s\" Until Unmounted, then \"%s\" Until Mounted\n"),
3598 dev->devnum, dev->tapemsg1, dev->tapemsg2 );
3599 }
3600 else
3601 {
3602 dev->tapedisptype = TAPEDISPTYP_MOUNT;
3603 dev->tapedispflags = TAPEDISPFLG_MESSAGE2 | TAPEDISPFLG_REQAUTOMNT;
3604
3605 if ( dev->ccwtrace || dev->ccwstep )
3606 logmsg(_("HHCTA099I %4.4X: Tape \"%s\" Until Mounted\n"),
3607 dev->devnum, dev->tapemsg2 );
3608 }
3609
3610 break;
3611 }
3612
3613 /* Set the flags... */
3614
3615 /*
3616 "When bit 7 (FCB_AL) is active and bits 0-2 (FCB_FS) specify
3617 a Mount Message, then only the first eight characters of the
3618 message are displayed and bits 3-5 (FCB_AM, FCB_BM, FCB_M2)
3619 are ignored."
3620 */
3621 if (1
3622 && ( fcb & FCB_AL )
3623 && ( ( fcb & FCB_FS ) == FCB_FS_MOUNT )
3624 )
3625 {
3626 fcb &= ~( FCB_AM | FCB_BM | FCB_M2 );
3627 dev->tapedispflags &= ~TAPEDISPFLG_MESSAGE2;
3628 }
3629
3630 /*
3631 "When bit 7 (FCB_AL) is active and bits 0-2 (FCB_FS) specify
3632 a Demount/Mount message, then only the last eight characters
3633 of the message are displayed. Bits 3-5 (FCB_AM, FCB_BM, FCB_M2)
3634 are ignored."
3635 */
3636 if (1
3637 && ( fcb & FCB_AL )
3638 && ( ( fcb & FCB_FS ) == FCB_FS_UMOUNTMOUNT )
3639 )
3640 {
3641 fcb &= ~( FCB_AM | FCB_BM | FCB_M2 );
3642 dev->tapedispflags |= TAPEDISPFLG_MESSAGE2;
3643 }
3644
3645 /*
3646 "When bit 3 (FCB_AM) is set to 1, then bits 4 (FCB_BM) and 5
3647 (FCB_M2) are ignored."
3648 */
3649 if ( fcb & FCB_AM )
3650 fcb &= ~( FCB_BM | FCB_M2 );
3651
3652 dev->tapedispflags |= (((fcb & FCB_AM) ? TAPEDISPFLG_ALTERNATE : 0 ) |
3653 ( (fcb & FCB_BM) ? TAPEDISPFLG_BLINKING : 0 ) |
3654 ( (fcb & FCB_M2) ? TAPEDISPFLG_MESSAGE2 : 0 ) |
3655 ( (fcb & FCB_AL) ? TAPEDISPFLG_AUTOLOADER : 0 ));
3656
3657 UpdateDisplay( dev );
3658 ReqAutoMount( dev );
3659
3660 } /* end function load_display */
3661
3662
3663 /*********************************************************************/
3664 /*********************************************************************/
3665 /** **/
3666 /** SENSE CCW HANDLING FUNCTIONS **/
3667 /** **/
3668 /*********************************************************************/
3669 /*********************************************************************/
3670
3671 /*-------------------------------------------------------------------*/
3672 /* build_senseX */
3673 /*-------------------------------------------------------------------*/
3674 /* Construct sense bytes and unit status */
3675 /* Note: name changed because semantic changed */
3676 /* ERCode is our internal ERror-type code */
3677 /* */
3678 /* Uses the 'TapeSenseTable' table index */
3679 /* from the 'TapeDevtypeList' table to route call to */
3680 /* one of the below device-specific sense functions */
3681 /*-------------------------------------------------------------------*/
build_senseX(int ERCode,DEVBLK * dev,BYTE * unitstat,BYTE ccwcode)3682 void build_senseX (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode)
3683 {
3684 int i;
3685 BYTE usr;
3686 int sense_built;
3687 sense_built = 0;
3688 if(unitstat==NULL)
3689 {
3690 unitstat = &usr;
3691 }
3692 for(i = 0;TapeDevtypeList[i] != 0; i += TAPEDEVTYPELIST_ENTRYSIZE)
3693 {
3694 if (TapeDevtypeList[i] == dev->devtype)
3695 {
3696 // Clear old sense if we're going to completely rebuild it...
3697
3698 if (TAPE_BSENSE_STATUSONLY != ERCode)
3699 {
3700 memset( dev->sense, 0, sizeof(dev->sense) );
3701 dev->sns_pending = 0;
3702 }
3703
3704 // Call the primary sense function (e.g. "build_sense_3480_etal")...
3705
3706 TapeSenseTable[TapeDevtypeList[i+4]](ERCode,dev,unitstat,ccwcode);
3707 sense_built = 1;
3708
3709 // Unit-exception s/b signalled for all write operations
3710 // once the end-of-tape (EOT) reflector has been passed...
3711
3712 if (1
3713 && TAPE_BSENSE_STATUSONLY == ERCode
3714 &&
3715 (0
3716 || 0x01 == ccwcode // write
3717 || 0x17 == ccwcode // erase gap
3718 || 0x1F == ccwcode // write tapemark
3719 )
3720 && dev->tmh->passedeot(dev)
3721 )
3722 {
3723 // We're still in the "Early Warning Zone",
3724 // so keep warning them...
3725
3726 *unitstat |= CSW_UX; // ("Warning!")
3727 }
3728 break;
3729 }
3730 }
3731 if (!sense_built)
3732 {
3733 memset( dev->sense, 0, sizeof(dev->sense) );
3734 dev->sense[0]=SENSE_EC;
3735 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3736 }
3737 if (*unitstat & CSW_UC)
3738 {
3739 dev->sns_pending = 1;
3740 }
3741 return;
3742
3743 } /* end function build_senseX */
3744
3745 /*-------------------------------------------------------------------*/
3746 /* build_sense_3410_3420 */
3747 /*-------------------------------------------------------------------*/
build_sense_3410_3420(int ERCode,DEVBLK * dev,BYTE * unitstat,BYTE ccwcode)3748 void build_sense_3410_3420 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode)
3749 {
3750 UNREFERENCED(ccwcode);
3751
3752 // NOTE: caller should have cleared sense area to zeros
3753 // if this isn't a 'TAPE_BSENSE_STATUSONLY' call
3754
3755 switch(ERCode)
3756 {
3757 case TAPE_BSENSE_TAPEUNLOADED:
3758 *unitstat = CSW_UC;
3759 dev->sense[0] = SENSE_IR;
3760 dev->sense[1] = SENSE1_TAPE_TUB;
3761 break;
3762 case TAPE_BSENSE_RUN_SUCCESS: /* RewUnld op */
3763 /* FIXME : CE Should have been presented before */
3764 /* Same as for 348x drives */
3765 *unitstat = CSW_CE | CSW_UC | CSW_DE | CSW_CUE;
3766 /*
3767 *unitstat = CSW_UC | CSW_DE | CSW_CUE;
3768 */
3769 dev->sense[0] = SENSE_IR;
3770 dev->sense[1] = SENSE1_TAPE_TUB;
3771 break;
3772 case TAPE_BSENSE_REWINDFAILED:
3773 case TAPE_BSENSE_FENCED:
3774 case TAPE_BSENSE_EMPTYTAPE:
3775 case TAPE_BSENSE_ENDOFTAPE:
3776 case TAPE_BSENSE_BLOCKSHORT:
3777 /* On 3411/3420 the tape runs off the reel in that case */
3778 /* this will cause pressure loss in both columns */
3779 case TAPE_BSENSE_LOCATEERR:
3780 /* Locate error: This is more like improperly formatted tape */
3781 /* i.e. the tape broke inside the drive */
3782 /* So EC instead of DC */
3783 case TAPE_BSENSE_TAPELOADFAIL:
3784 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3785 dev->sense[0] = SENSE_EC;
3786 dev->sense[1] = SENSE1_TAPE_TUB;
3787 dev->sense[7] = 0x60;
3788 break;
3789 case TAPE_BSENSE_ITFERROR:
3790 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3791 dev->sense[0] = SENSE_EC;
3792 dev->sense[1] = SENSE1_TAPE_TUB;
3793 dev->sense[4] = 0x80; /* Tape Unit Reject */
3794 break;
3795 case TAPE_BSENSE_READFAIL:
3796 case TAPE_BSENSE_BADALGORITHM:
3797 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3798 dev->sense[0] = SENSE_DC;
3799 dev->sense[3] = 0xC0; /* Vertical CRC check & Multitrack error */
3800 break;
3801 case TAPE_BSENSE_WRITEFAIL:
3802 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3803 dev->sense[0] = SENSE_DC;
3804 dev->sense[3] = 0x60; /* Longitudinal CRC check & Multitrack error */
3805 break;
3806 case TAPE_BSENSE_BADCOMMAND:
3807 case TAPE_BSENSE_INCOMPAT:
3808 *unitstat = CSW_UC;
3809 dev->sense[0] = SENSE_CR;
3810 dev->sense[4] = 0x01;
3811 break;
3812 case TAPE_BSENSE_WRITEPROTECT:
3813 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3814 dev->sense[0] = SENSE_CR;
3815 break;
3816 case TAPE_BSENSE_LOADPTERR:
3817 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3818 dev->sense[0] = 0;
3819 break;
3820 case TAPE_BSENSE_READTM:
3821 *unitstat = CSW_CE|CSW_DE|CSW_UX;
3822 break;
3823 case TAPE_BSENSE_UNSOLICITED:
3824 *unitstat = CSW_CE|CSW_DE;
3825 break;
3826 case TAPE_BSENSE_STATUSONLY:
3827 *unitstat = CSW_CE|CSW_DE;
3828 break;
3829 } // end switch(ERCode)
3830
3831 if (TAPE_BSENSE_STATUSONLY == ERCode)
3832 return; // (mission accomplished)
3833
3834 /* Fill in the common sense information */
3835
3836 if (strcmp(dev->filename,TAPE_UNLOADED) == 0
3837 || !dev->tmh->tapeloaded(dev,NULL,0))
3838 {
3839 dev->sense[0] |= SENSE_IR;
3840 dev->sense[1] |= SENSE1_TAPE_FP;
3841 dev->sense[1] &= ~SENSE1_TAPE_TUA;
3842 dev->sense[1] |= SENSE1_TAPE_TUB;
3843 }
3844 else
3845 {
3846 dev->sense[0] &= ~SENSE_IR;
3847 dev->sense[1] |= IsAtLoadPoint( dev ) ? SENSE1_TAPE_LOADPT : 0;
3848 dev->sense[1] |= dev->readonly || dev->tdparms.logical_readonly ?
3849 SENSE1_TAPE_FP : 0;
3850 dev->sense[1] |= SENSE1_TAPE_TUA;
3851 dev->sense[1] &= ~SENSE1_TAPE_TUB;
3852 }
3853 if (dev->tmh->passedeot(dev))
3854 {
3855 dev->sense[4] |= 0x40;
3856 }
3857
3858 } /* end function build_sense_3410_3420 */
3859
3860 /*-------------------------------------------------------------------*/
3861 /* build_sense_3410 */
3862 /*-------------------------------------------------------------------*/
build_sense_3410(int ERCode,DEVBLK * dev,BYTE * unitstat,BYTE ccwcode)3863 void build_sense_3410 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode)
3864 {
3865 build_sense_3410_3420(ERCode,dev,unitstat,ccwcode);
3866
3867 dev->sense[5] &= 0x80;
3868 dev->sense[5] |= 0x40;
3869 dev->sense[6] = 0x22; /* Dual Dens - 3410/3411 Model 2 */
3870 dev->numsense = 9;
3871
3872 } /* end function build_sense_3410 */
3873
3874 /*-------------------------------------------------------------------*/
3875 /* build_sense_3420 */
3876 /*-------------------------------------------------------------------*/
build_sense_3420(int ERCode,DEVBLK * dev,BYTE * unitstat,BYTE ccwcode)3877 void build_sense_3420 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode)
3878 {
3879 build_sense_3410_3420(ERCode,dev,unitstat,ccwcode);
3880
3881 /* Following stripped from original 'build_sense' */
3882 dev->sense[5] |= 0xC0;
3883 dev->sense[6] |= 0x03;
3884 dev->sense[13] = 0x80;
3885 dev->sense[14] = 0x01;
3886 dev->sense[15] = 0x00;
3887 dev->sense[16] = 0x01;
3888 dev->sense[19] = 0xFF;
3889 dev->sense[20] = 0xFF;
3890 dev->numsense = 24;
3891
3892 } /* end function build_sense_3420 */
3893
3894 /*-------------------------------------------------------------------*/
3895 /* build_sense_3480_etal */
3896 /*-------------------------------------------------------------------*/
build_sense_3480_etal(int ERCode,DEVBLK * dev,BYTE * unitstat,BYTE ccwcode)3897 void build_sense_3480_etal (int ERCode,DEVBLK *dev,BYTE *unitstat,BYTE ccwcode)
3898 {
3899 int sns4mat = TAPE_SNS7_FMT_20_3480;
3900
3901 // NOTE: caller should have cleared sense area to zeros
3902 // if this isn't a 'TAPE_BSENSE_STATUSONLY' call
3903
3904 switch(ERCode)
3905 {
3906 case TAPE_BSENSE_TAPEUNLOADED:
3907 dev->sense[0] = TAPE_SNS0_INTVREQ;
3908 dev->sense[3] = TAPE_ERA_DRIVE_NOT_READY; /* ERA 43 = Int Req */
3909 *unitstat = CSW_UC;
3910 break;
3911 case TAPE_BSENSE_RUN_SUCCESS: /* Not an error */
3912 /* NOT an error, But according to GA32-0219-02 2.1.2.2
3913 Rewind Unload always ends with with DE+UC on secondary status */
3914 /* FIXME! */
3915 /* Note that Initial status & Secondary statuses are merged here */
3916 /* when they should be presented separatly */
3917 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3918 dev->sense[0] = TAPE_SNS0_INTVREQ;
3919 dev->sense[3] = TAPE_ERA_ENVIRONMENTAL_DATA_PRESENT;
3920 sns4mat = TAPE_SNS7_FMT_22_3480_EOV_STATS;
3921 break;
3922 case TAPE_BSENSE_TAPELOADFAIL:
3923 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3924 dev->sense[0] = TAPE_SNS0_INTVREQ|TAPE_SNS0_DEFUNITCK;
3925 dev->sense[3] = TAPE_ERA_LOAD_FAILURE; /* ERA 33 = Load Failed */
3926 break;
3927 case TAPE_BSENSE_READFAIL:
3928 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3929 dev->sense[0] = TAPE_SNS0_DATACHK;
3930 dev->sense[3] = TAPE_ERA_READ_DATA_CHECK;
3931 break;
3932 case TAPE_BSENSE_WRITEFAIL:
3933 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3934 dev->sense[0] = TAPE_SNS0_DATACHK;
3935 dev->sense[3] = TAPE_ERA_WRITE_DATA_CHECK;
3936 break;
3937 case TAPE_BSENSE_BADCOMMAND:
3938 *unitstat = CSW_UC;
3939 dev->sense[0] = TAPE_SNS0_CMDREJ;
3940 dev->sense[3] = TAPE_ERA_COMMAND_REJECT;
3941 break;
3942 case TAPE_BSENSE_INCOMPAT:
3943 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3944 dev->sense[0] = TAPE_SNS0_CMDREJ;
3945 dev->sense[3] = TAPE_ERA_FUNCTION_INCOMPATIBLE;
3946 break;
3947 case TAPE_BSENSE_WRITEPROTECT:
3948 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3949 dev->sense[0] = TAPE_SNS0_CMDREJ;
3950 dev->sense[3] = TAPE_ERA_WRITE_PROTECTED;
3951 break;
3952 case TAPE_BSENSE_EMPTYTAPE:
3953 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3954 dev->sense[0] = TAPE_SNS0_DATACHK;
3955 dev->sense[3] = TAPE_ERA_TAPE_VOID;
3956 break;
3957 case TAPE_BSENSE_ENDOFTAPE:
3958 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3959 dev->sense[0] = TAPE_SNS0_EQUIPCHK;
3960 dev->sense[3] = TAPE_ERA_PHYSICAL_END_OF_TAPE;
3961 break;
3962 case TAPE_BSENSE_LOADPTERR:
3963 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3964 dev->sense[0] = 0;
3965 dev->sense[3] = TAPE_ERA_BACKWARD_AT_BOT;
3966 break;
3967 case TAPE_BSENSE_FENCED:
3968 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3969 dev->sense[0] = TAPE_SNS0_EQUIPCHK|TAPE_SNS0_DEFUNITCK; /* Deffered UC */
3970 dev->sense[3] = TAPE_ERA_VOLUME_FENCED;
3971 break;
3972 case TAPE_BSENSE_BADALGORITHM:
3973 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3974 dev->sense[0] = TAPE_SNS0_EQUIPCHK;
3975 if (dev->devtype==0x3480)
3976 {
3977 dev->sense[3] = TAPE_ERA_VOLUME_FENCED; // (volume fenced)
3978 }
3979 else // 3490, 3590, etc.
3980 {
3981 dev->sense[3] = TAPE_ERA_COMPACT_ALGORITHM_INCOMPAT; // (bad compaction algorithm)
3982 }
3983 break;
3984 case TAPE_BSENSE_LOCATEERR:
3985 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3986 dev->sense[0] = TAPE_SNS0_EQUIPCHK;
3987 dev->sense[3] = TAPE_ERA_LOCATE_BLOCK_FAILED;
3988 break;
3989 case TAPE_BSENSE_BLOCKSHORT:
3990 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3991 dev->sense[0] = TAPE_SNS0_EQUIPCHK;
3992 dev->sense[3] = TAPE_ERA_END_OF_DATA;
3993 break;
3994 case TAPE_BSENSE_ITFERROR:
3995 *unitstat = CSW_CE|CSW_DE|CSW_UC;
3996 dev->sense[0] = TAPE_SNS0_EQUIPCHK;
3997 dev->sense[3] = TAPE_ERA_PATH_EQUIPMENT_CHECK;
3998 break;
3999 case TAPE_BSENSE_REWINDFAILED:
4000 *unitstat = CSW_CE|CSW_DE|CSW_UC;
4001 dev->sense[0] = TAPE_SNS0_EQUIPCHK;
4002 dev->sense[3] = TAPE_ERA_PERMANENT_EQUIPMENT_CHECK; /* Generic Equipment Malfunction ERP code */
4003 break;
4004 case TAPE_BSENSE_READTM:
4005 *unitstat = CSW_CE|CSW_DE|CSW_UX;
4006 break;
4007 case TAPE_BSENSE_UNSOLICITED:
4008 *unitstat = CSW_CE|CSW_DE;
4009 dev->sense[3] = TAPE_ERA_UNSOLICITED_SENSE;
4010 break;
4011 case TAPE_BSENSE_STATUSONLY:
4012 default:
4013 if ( ccwcode == 0x24 ) // READ BUFFERED LOG
4014 {
4015 if ( dev->tdparms.compress == 0 )
4016 sns4mat = TAPE_SNS7_FMT_21_3480_READ_BUF_LOG;
4017 else
4018 sns4mat = TAPE_SNS7_FMT_30_3480_READ_BUF_LOG;
4019 }
4020 *unitstat = CSW_CE|CSW_DE;
4021 break;
4022 } // end switch(ERCode)
4023
4024 if (TAPE_BSENSE_STATUSONLY == ERCode)
4025 return; // (mission accomplished)
4026
4027 /* Fill in the common sense information */
4028
4029 if ( sns4mat == TAPE_SNS7_FMT_20_3480 ||
4030 sns4mat == TAPE_SNS7_FMT_21_3480_READ_BUF_LOG ||
4031 sns4mat == TAPE_SNS7_FMT_22_3480_EOV_STATS ||
4032 sns4mat == TAPE_SNS7_FMT_30_3480_READ_BUF_LOG )
4033 {
4034 dev->sense[7] = sns4mat;
4035 memset(&dev->sense[8],0,31-8);
4036
4037 if ( sns4mat == TAPE_SNS7_FMT_20_3480 )
4038 {
4039 dev->sense[25] = 0x06; // IDRC Installed & Upgraded Buffer
4040 if ( sysblk.tamdir != NULL ) // is AUTOLOADER ENABLED
4041 {
4042 dev->sense[25] |= 0x01; // ACL is installed
4043 }
4044 }
4045
4046 if ( dev->devtype == 0x3480 )
4047 {
4048 dev->sense[27] = 0xf0; // indicate 3480-A22/B22
4049 }
4050 else if ( dev->devtype==0x3490 )
4051 {
4052 dev->sense[27] = 0xe0; // indicate 3490-D31/D32
4053 }
4054 else if ( dev->devtype==0x3590 )
4055 {
4056 dev->sense[27] = 0xe0; // indicate same as 3490 for now
4057 }
4058
4059 /* create a serial Number */
4060 dev->sense[27] |= 0x0C;
4061 dev->sense[28] = (BYTE)( ( dev->devnum >> 12 ) & 0xFF );
4062 dev->sense[29] = (BYTE)( ( dev->devnum >> 4 ) & 0xFF );
4063
4064 dev->sense[30] = (BYTE)( dev->devnum & 0x000F ) | ( (BYTE)((BYTE)( dev->devnum & 0x000F )) << 4 );
4065 }
4066
4067 if (strcmp(dev->filename,TAPE_UNLOADED) == 0
4068 || !dev->tmh->tapeloaded(dev,NULL,0))
4069 {
4070 dev->sense[0] |= TAPE_SNS0_INTVREQ;
4071 dev->sense[1] |= TAPE_SNS1_FILEPROT;
4072 }
4073 else
4074 {
4075 dev->sense[0] &= ~TAPE_SNS0_INTVREQ;
4076 dev->sense[1] &= ~(TAPE_SNS1_BOT|TAPE_SNS1_FILEPROT);
4077 dev->sense[1] |= IsAtLoadPoint( dev ) ? TAPE_SNS1_BOT : 0;
4078 dev->sense[1] |= dev->readonly || dev->tdparms.logical_readonly ?
4079 TAPE_SNS1_FILEPROT : 0;
4080 }
4081
4082 dev->sense[1] |= TAPE_SNS1_ONLINE;
4083 dev->sense[2] |= TAPE_SNS2_REPORTING_CHAN_A;
4084
4085 } /* end function build_sense_3480_etal */
4086
4087 /*-------------------------------------------------------------------*/
4088 /* build_sense_3490 */
4089 /*-------------------------------------------------------------------*/
build_sense_3490(int ERCode,DEVBLK * dev,BYTE * unitstat,BYTE ccwcode)4090 void build_sense_3490 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode)
4091 {
4092 // Until we know for sure that we have to do something different,
4093 // we should be able to safely use the 3480 sense function here...
4094
4095 build_sense_3480_etal( ERCode, dev, unitstat, ccwcode );
4096 }
4097
4098 /*-------------------------------------------------------------------*/
4099 /* build_sense_3590 */
4100 /*-------------------------------------------------------------------*/
build_sense_3590(int ERCode,DEVBLK * dev,BYTE * unitstat,BYTE ccwcode)4101 void build_sense_3590 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode)
4102 {
4103 unsigned char ERA;
4104 // Until we know for sure that we have to do something different,
4105 // we should be able to safely use the 3480 sense function here...
4106
4107 build_sense_3480_etal( ERCode, dev, unitstat, ccwcode );
4108
4109 ERA = dev->sense[3];
4110 switch ( ERA )
4111 {
4112 case TAPE_ERA_LOAD_DISPLAY_CHECK:
4113 case TAPE_ERA_ENVIRONMENTAL_DATA_PRESENT:
4114 case TAPE_ERA_READ_BUFFERED_LOG:
4115 case TAPE_ERA_END_OF_VOLUME_PROCESSING:
4116 case TAPE_ERA_END_OF_VOLUME_COMPLETE:
4117 dev->sense[2] |= TAPE_SNS2_NTP_BRAC_01_CONTINUE;
4118 break;
4119 case TAPE_ERA_DATA_STREAMING_NOT_OPER:
4120 case TAPE_ERA_UNSOL_ENVIRONMENTAL_DATA:
4121 case TAPE_ERA_DEGRADED_MODE:
4122 case TAPE_ERA_RECOVERED_CHECKONE_FAILURE:
4123 case TAPE_ERA_CONTROLLING_COMP_RETRY_REQ:
4124 dev->sense[2] |= TAPE_SNS2_NTP_BRAC_10_REISSUE;
4125 break;
4126 default:
4127 dev->sense[2] |= TAPE_SNS2_NTP_BRAC_00_PERM_ERR;
4128 break;
4129 }
4130 }
4131
4132 /*-------------------------------------------------------------------*/
4133 /* build_sense_Streaming */
4134 /* (8809, 9347, 9348) */
4135 /*-------------------------------------------------------------------*/
build_sense_Streaming(int ERCode,DEVBLK * dev,BYTE * unitstat,BYTE ccwcode)4136 void build_sense_Streaming (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode)
4137 {
4138 UNREFERENCED(ccwcode);
4139
4140 // NOTE: caller should have cleared sense area to zeros
4141 // if this isn't a 'TAPE_BSENSE_STATUSONLY' call
4142
4143 switch(ERCode)
4144 {
4145 case TAPE_BSENSE_TAPEUNLOADED:
4146 *unitstat = CSW_UC;
4147 dev->sense[0] = SENSE_IR;
4148 dev->sense[3] = 6; /* Int Req ERAC */
4149 break;
4150 case TAPE_BSENSE_RUN_SUCCESS: /* RewUnld op */
4151 *unitstat = CSW_UC | CSW_CE | CSW_DE | CSW_CUE;
4152 /*
4153 *unitstat = CSW_CE | CSW_UC | CSW_DE | CSW_CUE;
4154 */
4155 dev->sense[0] = SENSE_IR;
4156 dev->sense[3] = 6; /* Int Req ERAC */
4157 break;
4158 case TAPE_BSENSE_REWINDFAILED:
4159 case TAPE_BSENSE_ITFERROR:
4160 dev->sense[0] = SENSE_EC;
4161 dev->sense[3] = 0x03; /* Perm Equip Check */
4162 *unitstat = CSW_CE|CSW_DE|CSW_UC;
4163 break;
4164 case TAPE_BSENSE_TAPELOADFAIL:
4165 case TAPE_BSENSE_LOCATEERR:
4166 case TAPE_BSENSE_ENDOFTAPE:
4167 case TAPE_BSENSE_EMPTYTAPE:
4168 case TAPE_BSENSE_FENCED:
4169 case TAPE_BSENSE_BLOCKSHORT:
4170 case TAPE_BSENSE_INCOMPAT:
4171 dev->sense[0] = SENSE_EC;
4172 dev->sense[3] = 0x10; /* PE-ID Burst Check */
4173 *unitstat = CSW_CE|CSW_DE|CSW_UC;
4174 break;
4175 case TAPE_BSENSE_BADALGORITHM:
4176 case TAPE_BSENSE_READFAIL:
4177 dev->sense[0] = SENSE_DC;
4178 dev->sense[3] = 0x09; /* Read Data Check */
4179 *unitstat = CSW_CE|CSW_DE|CSW_UC;
4180 break;
4181 case TAPE_BSENSE_WRITEFAIL:
4182 dev->sense[0] = SENSE_DC;
4183 dev->sense[3] = 0x07; /* Write Data Check (Media Error) */
4184 *unitstat = CSW_CE|CSW_DE|CSW_UC;
4185 break;
4186 case TAPE_BSENSE_BADCOMMAND:
4187 dev->sense[0] = SENSE_CR;
4188 dev->sense[3] = 0x0C; /* Bad Command */
4189 *unitstat = CSW_UC;
4190 break;
4191 case TAPE_BSENSE_WRITEPROTECT:
4192 dev->sense[0] = SENSE_CR;
4193 dev->sense[3] = 0x0B; /* File Protect */
4194 *unitstat = CSW_CE|CSW_DE|CSW_UC;
4195 break;
4196 case TAPE_BSENSE_LOADPTERR:
4197 dev->sense[0] = SENSE_CR;
4198 dev->sense[3] = 0x0D; /* Backspace at Load Point */
4199 *unitstat = CSW_CE|CSW_DE|CSW_UC;
4200 break;
4201 case TAPE_BSENSE_READTM:
4202 *unitstat = CSW_CE|CSW_DE|CSW_UX;
4203 break;
4204 case TAPE_BSENSE_UNSOLICITED:
4205 *unitstat = CSW_CE|CSW_DE;
4206 break;
4207 case TAPE_BSENSE_STATUSONLY:
4208 *unitstat = CSW_CE|CSW_DE;
4209 break;
4210 } // end switch(ERCode)
4211
4212 if (TAPE_BSENSE_STATUSONLY == ERCode)
4213 return; // (mission accomplished)
4214
4215 /* Fill in the common sense information */
4216
4217 if (strcmp(dev->filename,TAPE_UNLOADED) == 0
4218 || !dev->tmh->tapeloaded(dev,NULL,0))
4219 {
4220 dev->sense[0] |= SENSE_IR;
4221 dev->sense[1] |= SENSE1_TAPE_FP;
4222 dev->sense[1] &= ~SENSE1_TAPE_TUA;
4223 dev->sense[1] |= SENSE1_TAPE_TUB;
4224 }
4225 else
4226 {
4227 dev->sense[0] &= ~SENSE_IR;
4228 dev->sense[1] |= IsAtLoadPoint( dev ) ? SENSE1_TAPE_LOADPT : 0;
4229 dev->sense[1] |= dev->readonly || dev->tdparms.logical_readonly ?
4230 SENSE1_TAPE_FP : 0;
4231 dev->sense[1] |= SENSE1_TAPE_TUA;
4232 dev->sense[1] &= ~SENSE1_TAPE_TUB;
4233 }
4234 if (dev->tmh->passedeot(dev))
4235 {
4236 dev->sense[4] |= 0x40;
4237 }
4238
4239 } /* end function build_sense_Streaming */
4240
4241
4242 /*********************************************************************/
4243 /*********************************************************************/
4244 /** **/
4245 /** (( I N C O M P L E T E )) **/
4246 /** **/
4247 /** (experimental possible new sense handling function) **/
4248 /** **/
4249 /*********************************************************************/
4250 /*********************************************************************/
4251
4252 #if 0 // ZZ FIXME: To Do...
4253
4254 /*-------------------------------------------------------------------*/
4255 /* Error Recovery Action codes */
4256 /*-------------------------------------------------------------------*/
4257 /*
4258 Even though ERA codes are, technically, only applicable for
4259 model 3480/3490/3590 tape drives (the sense information that
4260 is returned for model 3480/3490/3590 tape drives include the
4261 ERA code in them), we can nonetheless still use them as an
4262 argument for our 'BuildTapeSense' function even for other
4263 model tape drives (e.g. 3420's for example). That is to say,
4264 even though model 3420's for example, don't have an ERA code
4265 anywhere in their sense information, we can still use the
4266 ERA code as an argument in our call to our 'BuildTapeSense'
4267 function without actually using it anywhere in our sense info.
4268 In such a case we would be just using it as an internal value
4269 to tell us what type of sense information to build for the
4270 model 3420, but not for any other purpose. For 3480/3490/3590
4271 model drives however, we not only use it for the same purpose
4272 (i.e. as an internal value to tell us what format of sense
4273 we need to build) but ALSO as an actual value to be placed
4274 into the actual formatted sense information itself too.
4275 */
4276
4277 #define TAPE_ERA_UNSOLICITED_SENSE 0x00
4278
4279 #define TAPE_ERA_DATA_STREAMING_NOT_OPER 0x21
4280 #define TAPE_ERA_PATH_EQUIPMENT_CHECK 0x22
4281 #define TAPE_ERA_READ_DATA_CHECK 0x23
4282 #define TAPE_ERA_LOAD_DISPLAY_CHECK 0x24
4283 #define TAPE_ERA_WRITE_DATA_CHECK 0x25
4284 #define TAPE_ERA_READ_OPPOSITE 0x26
4285 #define TAPE_ERA_COMMAND_REJECT 0x27
4286 #define TAPE_ERA_WRITE_ID_MARK_CHECK 0x28
4287 #define TAPE_ERA_FUNCTION_INCOMPATIBLE 0x29
4288 #define TAPE_ERA_UNSOL_ENVIRONMENTAL_DATA 0x2A
4289 #define TAPE_ERA_ENVIRONMENTAL_DATA_PRESENT 0x2B
4290 #define TAPE_ERA_PERMANENT_EQUIPMENT_CHECK 0x2C
4291 #define TAPE_ERA_DATA_SECURE_ERASE_FAILURE 0x2D
4292 #define TAPE_ERA_NOT_CAPABLE_BOT_ERROR 0x2E
4293
4294 #define TAPE_ERA_WRITE_PROTECTED 0x30
4295 #define TAPE_ERA_TAPE_VOID 0x31
4296 #define TAPE_ERA_TENSION_LOST 0x32
4297 #define TAPE_ERA_LOAD_FAILURE 0x33
4298 #define TAPE_ERA_UNLOAD_FAILURE 0x34
4299 #define TAPE_ERA_DRIVE_EQUIPMENT_CHECK 0x35
4300 #define TAPE_ERA_END_OF_DATA 0x36
4301 #define TAPE_ERA_TAPE_LENGTH_ERROR 0x37
4302 #define TAPE_ERA_PHYSICAL_END_OF_TAPE 0x38
4303 #define TAPE_ERA_BACKWARD_AT_BOT 0x39
4304 #define TAPE_ERA_DRIVE_SWITCHED_NOT_READY 0x3A
4305 #define TAPE_ERA_MANUAL_REWIND_OR_UNLOAD 0x3B
4306
4307 #define TAPE_ERA_OVERRUN 0x40
4308 #define TAPE_ERA_RECORD_SEQUENCE_ERROR 0x41
4309 #define TAPE_ERA_DEGRADED_MODE 0x42
4310 #define TAPE_ERA_DRIVE_NOT_READY 0x43
4311 #define TAPE_ERA_LOCATE_BLOCK_FAILED 0x44
4312 #define TAPE_ERA_DRIVE_ASSIGNED_ELSEWHERE 0x45
4313 #define TAPE_ERA_DRIVE_NOT_ONLINE 0x46
4314 #define TAPE_ERA_VOLUME_FENCED 0x47
4315 #define TAPE_ERA_UNSOL_INFORMATIONAL_DATA 0x48
4316 #define TAPE_ERA_BUS_OUT_CHECK 0x49
4317 #define TAPE_ERA_CONTROL_UNIT_ERP_FAILURE 0x4A
4318 #define TAPE_ERA_CU_AND_DRIVE_INCOMPATIBLE 0x4B
4319 #define TAPE_ERA_RECOVERED_CHECKONE_FAILED 0x4C
4320 #define TAPE_ERA_RESETTING_EVENT 0x4D
4321 #define TAPE_ERA_MAX_BLOCKSIZE_EXCEEDED 0x4E
4322
4323 #define TAPE_ERA_BUFFERED_LOG_OVERFLOW 0x50
4324 #define TAPE_ERA_BUFFERED_LOG_END_OF_VOLUME 0x51
4325 #define TAPE_ERA_END_OF_VOLUME_COMPLETE 0x52
4326 #define TAPE_ERA_GLOBAL_COMMAND_INTERCEPT 0x53
4327 #define TAPE_ERA_TEMP_CHANN_INTFACE_ERROR 0x54
4328 #define TAPE_ERA_PERM_CHANN_INTFACE_ERROR 0x55
4329 #define TAPE_ERA_CHANN_PROTOCOL_ERROR 0x56
4330 #define TAPE_ERA_GLOBAL_STATUS_INTERCEPT 0x57
4331 #define TAPE_ERA_TAPE_LENGTH_INCOMPATIBLE 0x5A
4332 #define TAPE_ERA_FORMAT_3480_XF_INCOMPAT 0x5B
4333 #define TAPE_ERA_FORMAT_3480_2_XF_INCOMPAT 0x5C
4334 #define TAPE_ERA_TAPE_LENGTH_VIOLATION 0x5D
4335 #define TAPE_ERA_COMPACT_ALGORITHM_INCOMPAT 0x5E
4336
4337 // Sense byte 0
4338
4339 #define TAPE_SNS0_CMDREJ 0x80 // Command Reject
4340 #define TAPE_SNS0_INTVREQ 0x40 // Intervention Required
4341 #define TAPE_SNS0_BUSCHK 0x20 // Bus-out Check
4342 #define TAPE_SNS0_EQUIPCHK 0x10 // Equipment Check
4343 #define TAPE_SNS0_DATACHK 0x08 // Data check
4344 #define TAPE_SNS0_OVERRUN 0x04 // Overrun
4345 #define TAPE_SNS0_DEFUNITCK 0x02 // Deferred Unit Check
4346 #define TAPE_SNS0_ASSIGNED 0x01 // Assigned Elsewhere
4347
4348 // Sense byte 1
4349
4350 #define TAPE_SNS1_LOCFAIL 0x80 // Locate Failure
4351 #define TAPE_SNS1_ONLINE 0x40 // Drive Online to CU
4352 #define TAPE_SNS1_RSRVD 0x20 // Reserved
4353 #define TAPE_SNS1_RCDSEQ 0x10 // Record Sequence Error
4354 #define TAPE_SNS1_BOT 0x08 // Beginning of Tape
4355 #define TAPE_SNS1_WRTMODE 0x04 // Write Mode
4356 #define TAPE_SNS1_FILEPROT 0x02 // Write Protect
4357 #define TAPE_SNS1_NOTCAPBL 0x01 // Not Capable
4358
4359 // Sense byte 2
4360
4361 //efine TAPE_SNS2_XXXXXXX 0x80-0x04 // (not defined)
4362 #define TAPE_SNS2_SYNCMODE 0x02 // Tape Synchronous Mode
4363 #define TAPE_SNS2_POSITION 0x01 // Tape Positioning
4364
4365 #define BUILD_TAPE_SENSE( _era ) BuildTapeSense( _era, dev, unitstat, code )
4366 // BUILD_TAPE_SENSE( TAPE_ERA_COMMAND_REJECT );
4367
4368
4369 /*-------------------------------------------------------------------*/
4370 /* BuildTapeSense */
4371 /*-------------------------------------------------------------------*/
4372 /* Build appropriate sense information based on passed ERA code... */
4373 /*-------------------------------------------------------------------*/
4374
4375 void BuildTapeSense( BYTE era, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode )
4376 {
4377 BYTE fmt;
4378
4379 // ---------------- Determine Sense Format -----------------------
4380
4381 switch (era)
4382 {
4383 default:
4384
4385 fmt = 0x20;
4386 break;
4387
4388 case TAPE_ERA_UNSOL_ENVIRONMENTAL_DATA: // ERA 2A
4389
4390 fmt = 0x21;
4391 break;
4392
4393 case TAPE_ERA_ENVIRONMENTAL_DATA_PRESENT: // ERA 2B
4394
4395 if (dev->devchar[8] & 0x01) // Extended Buffered Log support enabled?
4396 fmt = 0x30; // Yes, IDRC; 64-bytes of sense data
4397 else
4398 fmt = 0x21; // No, no IDRC; only 32-bytes of sense
4399 break;
4400
4401 case TAPE_ERA_UNSOL_INFORMATIONAL_DATA: // ERA 48
4402
4403 if (dev->forced_logging) // Forced Error Logging enabled?
4404 fmt = 0x19; // Yes, Forced Error Logging sense
4405 else
4406 fmt = 0x20; // No, Normal Informational sense
4407 break;
4408
4409 case TAPE_ERA_END_OF_VOLUME_COMPLETE: // ERA 52
4410
4411 fmt = 0x22;
4412 break;
4413
4414 case TAPE_ERA_FORMAT_3480_2_XF_INCOMPAT: // ERA 5C
4415
4416 fmt = 0x24;
4417 break;
4418
4419 } // End switch (era)
4420
4421 // ---------------- Build Sense Format -----------------------
4422
4423 switch (fmt)
4424 {
4425 case 0x19:
4426 break;
4427
4428 default:
4429 case 0x20:
4430 break;
4431
4432 case 0x21:
4433 break;
4434
4435 case 0x22:
4436 break;
4437
4438 case 0x24:
4439 break;
4440
4441 case 0x30:
4442 break;
4443
4444 } // End switch (fmt)
4445
4446 } /* end function BuildTapeSense */
4447
4448
4449 #endif // ZZ FIXME: To Do...
4450
4451
4452 /*********************************************************************/
4453 /*********************************************************************/
4454