1 /* FBADASD.C (c) Copyright Roger Bowler, 1999-2009 */
2 /* ESA/390 FBA Direct Access Storage Device Handler */
3
4 /*-------------------------------------------------------------------*/
5 /* This module contains device handling functions for emulated */
6 /* fixed block architecture direct access storage devices. */
7 /*-------------------------------------------------------------------*/
8
9 /*-------------------------------------------------------------------*/
10 /* Additional credits: */
11 /* 0671 device support by Jay Maynard */
12 /*-------------------------------------------------------------------*/
13
14 #include "hstdinc.h"
15
16 #define _FBADASD_C_
17 #define _HDASD_DLL_
18
19 #include "hercules.h"
20 #include "dasdblks.h" // (need #define DEFAULT_FBA_TYPE)
21 #include "sr.h"
22
23 /*-------------------------------------------------------------------*/
24 /* Bit definitions for Define Extent file mask */
25 /*-------------------------------------------------------------------*/
26 #define FBAMASK_CTL 0xC0 /* Operation control bits... */
27 #define FBAMASK_CTL_INHFMT 0x00 /* ...inhibit format writes */
28 #define FBAMASK_CTL_INHWRT 0x40 /* ...inhibit all writes */
29 #define FBAMASK_CTL_ALLWRT 0xC0 /* ...allow all writes */
30 #define FBAMASK_CTL_RESV 0x80 /* ...reserved bit setting */
31 #define FBAMASK_CE 0x08 /* CE field extent */
32 #define FBAMASK_DIAG 0x04 /* Permit diagnostic command */
33 #define FBAMASK_RESV 0x33 /* Reserved bits - must be 0 */
34
35 /*-------------------------------------------------------------------*/
36 /* Bit definitions for Locate operation byte */
37 /*-------------------------------------------------------------------*/
38 #define FBAOPER_RESV 0xE0 /* Reserved bits - must be 0 */
39 /* Note : Bit 3 seems to be */
40 /* The "suppress" bit but is */
41 /* apparently ignored */
42 /* It is therefore valid but */
43 /* not used. */
44 #define FBAOPER_CODE 0x0F /* Operation code bits... */
45 #define FBAOPER_WRITE 0x01 /* ...write data */
46 #define FBAOPER_READREP 0x02 /* ...read replicated data */
47 #define FBAOPER_FMTDEFC 0x04 /* ...format defective block */
48 #define FBAOPER_WRTVRFY 0x05 /* ...write data and verify */
49 #define FBAOPER_READ 0x06 /* ...read data */
50
51 #define FBA_BLKGRP_SIZE (120 * 512) /* Size of block group */
52
53 /*-------------------------------------------------------------------*/
54 /* Initialize the device handler */
55 /*-------------------------------------------------------------------*/
fbadasd_init_handler(DEVBLK * dev,int argc,char * argv[])56 int fbadasd_init_handler ( DEVBLK *dev, int argc, char *argv[] )
57 {
58 int rc; /* Return code */
59 struct stat statbuf; /* File information */
60 int startblk; /* Device origin block number*/
61 int numblks; /* Device block count */
62 BYTE c; /* Character work area */
63 char *cu = NULL; /* Specified control unit */
64 char *kw; /* Argument keyword */
65 int cfba = 0; /* 1 = Compressed fba */
66 int i; /* Loop index */
67 CKDDASD_DEVHDR devhdr; /* Device header */
68 CCKDDASD_DEVHDR cdevhdr; /* Compressed device header */
69 char pathname[MAX_PATH]; /* file path in host format */
70
71 if (!dev->typname || !sscanf(dev->typname,"%hx",&(dev->devtype)))
72 dev->devtype = DEFAULT_FBA_TYPE;
73
74 /* The first argument is the file name */
75 if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1)
76 {
77 logmsg (_("HHCDA056E File name missing or invalid\n"));
78 return -1;
79 }
80
81 /* Save the file name in the device block */
82 strcpy (dev->filename, argv[0]);
83
84 /* Device is shareable */
85 dev->shared = 1;
86
87 /* Check for possible remote device */
88 hostpath(pathname, dev->filename, sizeof(pathname));
89 if (stat(pathname, &statbuf) < 0)
90 {
91 rc = shared_fba_init ( dev, argc, argv);
92 if (rc < 0)
93 {
94 logmsg (_("HHCDA057E %4.4X:File not found or invalid\n"),
95 dev->devnum);
96 return -1;
97 }
98 else
99 return rc;
100 }
101
102 /* Open the device file */
103 hostpath(pathname, dev->filename, sizeof(pathname));
104 dev->fd = hopen(pathname, O_RDWR|O_BINARY);
105 if (dev->fd < 0)
106 {
107 dev->fd = hopen(pathname, O_RDONLY|O_BINARY);
108 if (dev->fd < 0)
109 {
110 logmsg (_("HHCDA058E File %s open error: %s\n"),
111 dev->filename, strerror(errno));
112 return -1;
113 }
114 }
115
116 /* Read the first block to see if it's compressed */
117 rc = read (dev->fd, &devhdr, CKDDASD_DEVHDR_SIZE);
118 if (rc < (int)CKDDASD_DEVHDR_SIZE)
119 {
120 /* Handle read error condition */
121 if (rc < 0)
122 logmsg (_("HHCDA059E Read error in file %s: %s\n"),
123 dev->filename, strerror(errno));
124 else
125 logmsg (_("HHCDA060E Unexpected end of file in %s\n"),
126 dev->filename);
127 close (dev->fd);
128 dev->fd = -1;
129 return -1;
130 }
131
132 /* Processing for compressed fba dasd */
133 if (memcmp (&devhdr.devid, "FBA_C370", 8) == 0)
134 {
135 cfba = 1;
136
137 /* Read the compressed device header */
138 rc = read (dev->fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE);
139 if (rc < (int)CKDDASD_DEVHDR_SIZE)
140 {
141 /* Handle read error condition */
142 if (rc < 0)
143 logmsg (_("HHCDA061E Read error in file %s: %s\n"),
144 dev->filename, strerror(errno));
145 else
146 logmsg (_("HHCDA062E Unexpected end of file in %s\n"),
147 dev->filename);
148 close (dev->fd);
149 dev->fd = -1;
150 return -1;
151 }
152
153 /* Set block size, device origin, and device size in blocks */
154 dev->fbablksiz = 512;
155 dev->fbaorigin = 0;
156 dev->fbanumblk = ((U32)(cdevhdr.cyls[3]) << 24)
157 | ((U32)(cdevhdr.cyls[2]) << 16)
158 | ((U32)(cdevhdr.cyls[1]) << 8)
159 | (U32)(cdevhdr.cyls[0]);
160
161 /* Default to synchronous I/O */
162 //FIXME: syncio is reported to be broken for fba
163 // dev->syncio = 1;
164
165 /* process the remaining arguments */
166 for (i = 1; i < argc; i++)
167 {
168 if (strlen (argv[i]) > 3
169 && memcmp ("sf=", argv[i], 3) == 0)
170 {
171 if ('\"' == argv[i][3]) argv[i]++;
172 hostpath(pathname, argv[i]+3, sizeof(pathname));
173 dev->dasdsfn = strdup(pathname);
174 if (dev->dasdsfn)
175 {
176 /* Set the pointer to the suffix character */
177 dev->dasdsfx = strrchr (dev->dasdsfn, '/');
178 if (dev->dasdsfx == NULL)
179 dev->dasdsfx = dev->dasdsfn + 1;
180 dev->dasdsfx = strchr (dev->dasdsfx, '.');
181 if (dev->dasdsfx == NULL)
182 dev->dasdsfx = dev->dasdsfn + strlen(dev->dasdsfn);
183 dev->dasdsfx--;
184 }
185 continue;
186 }
187 if (strlen (argv[i]) > 3
188 && memcmp("cu=", argv[i], 3) == 0) /* support for cu= added but */
189 { /* is ignored for the present */
190 kw = strtok (argv[i], "=");
191 cu = strtok (NULL, " \t");
192 continue;
193 }
194 if (strcasecmp ("nosyncio", argv[i]) == 0
195 || strcasecmp ("nosyio", argv[i]) == 0)
196 {
197 dev->syncio = 0;
198 continue;
199 }
200 if (strcasecmp ("syncio", argv[i]) == 0
201 || strcasecmp ("syio", argv[i]) == 0)
202 {
203 dev->syncio = 1;
204 continue;
205 }
206
207 logmsg (_("HHCDA063E parameter %d is invalid: %s\n"),
208 i + 1, argv[i]);
209 return -1;
210 }
211 }
212
213 /* Processing for regular fba dasd */
214 else
215 {
216 /* Determine the device size */
217 rc = fstat (dev->fd, &statbuf);
218 if (rc < 0)
219 {
220 logmsg (_("HHCDA064E File %s fstat error: %s\n"),
221 dev->filename, strerror(errno));
222 close (dev->fd);
223 dev->fd = -1;
224 return -1;
225 }
226 #if defined(OPTION_FBA_BLKDEVICE) && defined(BLKGETSIZE)
227 if(S_ISBLK(statbuf.st_mode))
228 {
229 rc=ioctl(dev->fd,BLKGETSIZE,&statbuf.st_size);
230 if(rc<0)
231 {
232 logmsg (_("HHCDA082E File %s IOCTL BLKGETSIZE error: %s\n"),
233 dev->filename, strerror(errno));
234 close (dev->fd);
235 dev->fd = -1;
236 return -1;
237 }
238 dev->fbablksiz = 512;
239 dev->fbaorigin = 0;
240 dev->fbanumblk = statbuf.st_size;
241 logmsg("REAL FBA Opened\n");
242 }
243 else
244 #endif // defined(OPTION_FBA_BLKDEVICE) && defined(BLKGETSIZE)
245 {
246 /* Set block size, device origin, and device size in blocks */
247 dev->fbablksiz = 512;
248 dev->fbaorigin = 0;
249 dev->fbanumblk = statbuf.st_size / dev->fbablksiz;
250 }
251
252 /* The second argument is the device origin block number */
253 if (argc >= 2)
254 {
255 if (sscanf(argv[1], "%u%c", &startblk, &c) != 1
256 || startblk >= dev->fbanumblk)
257 {
258 logmsg (_("HHCDA065E Invalid device origin block number %s\n"),
259 argv[1]);
260 close (dev->fd);
261 dev->fd = -1;
262 return -1;
263 }
264 dev->fbaorigin = (off_t)startblk;
265 dev->fbanumblk -= startblk;
266 }
267
268 /* The third argument is the device block count */
269 if (argc >= 3 && strcmp(argv[2],"*") != 0)
270 {
271 if (sscanf(argv[2], "%u%c", &numblks, &c) != 1
272 || numblks > dev->fbanumblk)
273 {
274 logmsg (_("HHCDA066E Invalid device block count %s\n"),
275 argv[2]);
276 close (dev->fd);
277 dev->fd = -1;
278 return -1;
279 }
280 dev->fbanumblk = numblks;
281 }
282 }
283 dev->fbaend = (dev->fbaorigin + dev->fbanumblk) * dev->fbablksiz;
284
285 logmsg (_("HHCDA067I %s origin=%lld blks=%d\n"),
286 dev->filename, (long long)dev->fbaorigin, dev->fbanumblk);
287
288 /* Set number of sense bytes */
289 dev->numsense = 24;
290
291 /* Locate the FBA dasd table entry */
292 dev->fbatab = dasd_lookup (DASD_FBADEV, NULL, dev->devtype, dev->fbanumblk);
293 if (dev->fbatab == NULL)
294 {
295 logmsg (_("HHCDA068E %4.4X device type %4.4X not found in dasd table\n"),
296 dev->devnum, dev->devtype);
297 close (dev->fd);
298 dev->fd = -1;
299 return -1;
300 }
301
302 /* Build the devid area */
303 dev->numdevid = dasd_build_fba_devid (dev->fbatab,(BYTE *)&dev->devid);
304
305 /* Build the devchar area */
306 dev->numdevchar = dasd_build_fba_devchar (dev->fbatab,
307 (BYTE *)&dev->devchar,dev->fbanumblk);
308
309 /* Initialize current blkgrp and cache entry */
310 dev->bufcur = dev->cache = -1;
311
312 /* Activate I/O tracing */
313 // dev->ccwtrace = 1;
314
315 /* Call the compressed init handler if compressed fba */
316 if (cfba)
317 return cckddasd_init_handler (dev, argc, argv);
318
319 return 0;
320 } /* end function fbadasd_init_handler */
321
322 /*-------------------------------------------------------------------*/
323 /* Query the device definition */
324 /*-------------------------------------------------------------------*/
fbadasd_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)325 void fbadasd_query_device (DEVBLK *dev, char **class,
326 int buflen, char *buffer)
327 {
328
329 BEGIN_DEVICE_CLASS_QUERY( "DASD", dev, class, buflen, buffer );
330
331 snprintf (buffer, buflen, "%s [%lld,%d]",
332 dev->filename,
333 (long long)dev->fbaorigin, dev->fbanumblk);
334
335 } /* end function fbadasd_query_device */
336
337 /*-------------------------------------------------------------------*/
338 /* Calculate length of an FBA block group */
339 /*-------------------------------------------------------------------*/
fba_blkgrp_len(DEVBLK * dev,int blkgrp)340 static int fba_blkgrp_len (DEVBLK *dev, int blkgrp)
341 {
342 off_t offset; /* Offset of block group */
343
344 offset = blkgrp * FBA_BLKGRP_SIZE;
345 if (dev->fbaend - offset < FBA_BLKGRP_SIZE)
346 return (int)(dev->fbaend - offset);
347 else
348 return FBA_BLKGRP_SIZE;
349 }
350
351 /*-------------------------------------------------------------------*/
352 /* Read fba block(s) */
353 /*-------------------------------------------------------------------*/
fba_read(DEVBLK * dev,BYTE * buf,int len,BYTE * unitstat)354 static int fba_read (DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat)
355 {
356 int rc; /* Return code */
357 int blkgrp; /* Block group number */
358 int blklen; /* Length left in block group*/
359 int off; /* Device buffer offset */
360 int bufoff; /* Buffer offset */
361 int copylen; /* Length left to copy */
362
363 /* Command reject if referencing outside the volume */
364 if (dev->fbarba < dev->fbaorigin * dev->fbablksiz
365 || dev->fbarba + len > dev->fbaend)
366 {
367 dev->sense[0] = SENSE_CR;
368 *unitstat = CSW_CE | CSW_DE | CSW_UC;
369 return -1;
370 }
371
372 /* Read the block group */
373 blkgrp = dev->fbarba / FBA_BLKGRP_SIZE;
374 rc = (dev->hnd->read) (dev, blkgrp, unitstat);
375 if (rc < 0)
376 return -1;
377
378 off = dev->fbarba % FBA_BLKGRP_SIZE;
379 blklen = dev->buflen - off;
380
381 /* Initialize target buffer offset and length to copy */
382 bufoff = 0;
383 copylen = len;
384
385 /* Access multiple block groups asynchronously */
386 if (dev->syncio_active && copylen > blklen)
387 {
388 dev->syncio_retry = 1;
389 return -1;
390 }
391
392 /* Copy from the device buffer to the target buffer */
393 while (copylen > 0)
394 {
395 int len = copylen < blklen ? copylen : blklen;
396
397 /* Copy to the target buffer */
398 if (buf) memcpy (buf + bufoff, dev->buf + off, len);
399
400 /* Update offsets and lengths */
401 bufoff += len;
402 copylen -= blklen;
403
404 /* Read the next block group if still more to copy */
405 if (copylen > 0)
406 {
407 blkgrp++;
408 off = 0;
409 rc = (dev->hnd->read) (dev, blkgrp, unitstat);
410 if (rc < 0)
411 return -1;
412 blklen = fba_blkgrp_len (dev, blkgrp);
413 }
414 }
415
416 /* Update the rba */
417 dev->fbarba += len;
418
419 return len;
420 } /* end function fba_read */
421
422 /*-------------------------------------------------------------------*/
423 /* Write fba block(s) */
424 /*-------------------------------------------------------------------*/
fba_write(DEVBLK * dev,BYTE * buf,int len,BYTE * unitstat)425 static int fba_write (DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat)
426 {
427 int rc; /* Return code */
428 int blkgrp; /* Block group number */
429 int blklen; /* Length left in block group*/
430 int off; /* Target buffer offset */
431 int bufoff; /* Source buffer offset */
432 int copylen; /* Length left to copy */
433
434 /* Command reject if referencing outside the volume */
435 if (dev->fbarba < dev->fbaorigin * dev->fbablksiz
436 || dev->fbarba + len > dev->fbaend)
437 {
438 dev->sense[0] = SENSE_CR;
439 *unitstat = CSW_CE | CSW_DE | CSW_UC;
440 return -1;
441 }
442
443 /* Read the block group */
444 blkgrp = dev->fbarba / FBA_BLKGRP_SIZE;
445 rc = (dev->hnd->read) (dev, blkgrp, unitstat);
446 if (rc < 0)
447 return -1;
448
449 off = dev->fbarba % FBA_BLKGRP_SIZE;
450 blklen = dev->buflen - off;
451
452 /* Initialize source buffer offset and length to copy */
453 bufoff = 0;
454 copylen = len;
455
456 /* Access multiple block groups asynchronously */
457 if (dev->syncio_active && copylen > blklen)
458 {
459 dev->syncio_retry = 1;
460 return -1;
461 }
462
463 /* Copy to the device buffer from the target buffer */
464 while (copylen > 0)
465 {
466 int len = copylen < blklen ? copylen : blklen;
467
468 /* Write to the block group */
469 rc = (dev->hnd->write) (dev, blkgrp, off, buf + bufoff,
470 len, unitstat);
471 if (rc < 0)
472 return -1;
473
474 /* Update offsets and lengths */
475 bufoff += len;
476 copylen -= len;
477 blkgrp++;
478 off = 0;
479 blklen = fba_blkgrp_len (dev, blkgrp);
480 }
481
482 /* Update the rba */
483 dev->fbarba += len;
484
485 return len;
486 } /* end function fba_write */
487
488 /*-------------------------------------------------------------------*/
489 /* FBA read block group exit */
490 /*-------------------------------------------------------------------*/
491 static
fbadasd_read_blkgrp(DEVBLK * dev,int blkgrp,BYTE * unitstat)492 int fbadasd_read_blkgrp (DEVBLK *dev, int blkgrp, BYTE *unitstat)
493 {
494 int rc; /* Return code */
495 int i, o; /* Cache indexes */
496 int len; /* Length to read */
497 off_t offset; /* File offsets */
498
499 /* Return if reading the same block group */
500 if (blkgrp >= 0 && blkgrp == dev->bufcur)
501 return 0;
502
503 /* Write the previous block group if modified */
504 if (dev->bufupd)
505 {
506 /* Retry if synchronous I/O */
507 if (dev->syncio_active)
508 {
509 dev->syncio_retry = 1;
510 return -1;
511 }
512
513 dev->bufupd = 0;
514
515 /* Seek to the old block group offset */
516 offset = (off_t)(((S64)dev->bufcur * FBA_BLKGRP_SIZE) + dev->bufupdlo);
517 offset = lseek (dev->fd, offset, SEEK_SET);
518 if (offset < 0)
519 {
520 /* Handle seek error condition */
521 logmsg (_("HHCDA069E error writing blkgrp %d: lseek error: %s\n"),
522 dev->bufcur, strerror(errno));
523 dev->sense[0] = SENSE_EC;
524 *unitstat = CSW_CE | CSW_DE | CSW_UC;
525 cache_lock(CACHE_DEVBUF);
526 cache_setflag(CACHE_DEVBUF, dev->cache, ~FBA_CACHE_ACTIVE, 0);
527 cache_unlock(CACHE_DEVBUF);
528 dev->bufupdlo = dev->bufupdhi = 0;
529 dev->bufcur = dev->cache = -1;
530 return -1;
531 }
532
533 /* Write the portion of the block group that was modified */
534 rc = write (dev->fd, dev->buf + dev->bufupdlo,
535 dev->bufupdhi - dev->bufupdlo);
536 if (rc < dev->bufupdhi - dev->bufupdlo)
537 {
538 /* Handle write error condition */
539 logmsg (_("HHCDA070E error writing blkgrp %d: write error: %s\n"),
540 dev->bufcur, strerror(errno));
541 dev->sense[0] = SENSE_EC;
542 *unitstat = CSW_CE | CSW_DE | CSW_UC;
543 cache_lock(CACHE_DEVBUF);
544 cache_setflag(CACHE_DEVBUF, dev->cache, ~FBA_CACHE_ACTIVE, 0);
545 cache_unlock(CACHE_DEVBUF);
546 dev->bufupdlo = dev->bufupdhi = 0;
547 dev->bufcur = dev->cache = -1;
548 return -1;
549 }
550
551 dev->bufupdlo = dev->bufupdhi = 0;
552 }
553
554 cache_lock (CACHE_DEVBUF);
555
556 /* Make the previous cache entry inactive */
557 if (dev->cache >= 0)
558 cache_setflag(CACHE_DEVBUF, dev->cache, ~FBA_CACHE_ACTIVE, 0);
559 dev->bufcur = dev->cache = -1;
560
561 /* Return on special case when called by the close handler */
562 if (blkgrp < 0)
563 {
564 cache_unlock (CACHE_DEVBUF);
565 return 0;
566 }
567
568 fba_read_blkgrp_retry:
569
570 /* Search the cache */
571 i = cache_lookup (CACHE_DEVBUF, FBA_CACHE_SETKEY(dev->devnum, blkgrp), &o);
572
573 /* Cache hit */
574 if (i >= 0)
575 {
576 cache_setflag(CACHE_DEVBUF, i, ~0, FBA_CACHE_ACTIVE);
577 cache_setage(CACHE_DEVBUF, i);
578 cache_unlock(CACHE_DEVBUF);
579
580 logdevtr (dev, _("HHCDA071I read blkgrp %d cache hit, using cache[%d]\n"),
581 blkgrp, i);
582
583 dev->cachehits++;
584 dev->cache = i;
585 dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0);
586 dev->bufcur = blkgrp;
587 dev->bufoff = 0;
588 dev->bufoffhi = fba_blkgrp_len (dev, blkgrp);
589 dev->buflen = fba_blkgrp_len (dev, blkgrp);
590 dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache);
591 return 0;
592 }
593
594 /* Retry if synchronous I/O */
595 if (dev->syncio_active)
596 {
597 cache_unlock(CACHE_DEVBUF);
598 dev->syncio_retry = 1;
599 return -1;
600 }
601
602 /* Wait if no available cache entry */
603 if (o < 0)
604 {
605 logdevtr (dev, _("HHCDA072I read blkgrp %d no available cache entry, waiting\n"),
606 blkgrp);
607 dev->cachewaits++;
608 cache_wait(CACHE_DEVBUF);
609 goto fba_read_blkgrp_retry;
610 }
611
612 /* Cache miss */
613 logdevtr (dev, _("HHCDA073I read blkgrp %d cache miss, using cache[%d]\n"),
614 blkgrp, o);
615
616 dev->cachemisses++;
617
618 /* Make this cache entry active */
619 cache_setkey (CACHE_DEVBUF, o, FBA_CACHE_SETKEY(dev->devnum, blkgrp));
620 cache_setflag(CACHE_DEVBUF, o, 0, FBA_CACHE_ACTIVE|DEVBUF_TYPE_FBA);
621 cache_setage (CACHE_DEVBUF, o);
622 dev->buf = cache_getbuf(CACHE_DEVBUF, o, FBA_BLKGRP_SIZE);
623 cache_unlock (CACHE_DEVBUF);
624
625 /* Get offset and length */
626 offset = (off_t)((S64)blkgrp * FBA_BLKGRP_SIZE);
627 len = fba_blkgrp_len (dev, blkgrp);
628
629 logdevtr (dev, _("HHCDA074I read blkgrp %d offset %" I64_FMT "d len %d\n"),
630 blkgrp, (long long)offset, fba_blkgrp_len(dev, blkgrp));
631
632 /* Seek to the block group offset */
633 offset = lseek (dev->fd, offset, SEEK_SET);
634 if (offset < 0)
635 {
636 /* Handle seek error condition */
637 logmsg (_("HHCDA075E error reading blkgrp %d: lseek error: %s\n"),
638 blkgrp, strerror(errno));
639 dev->sense[0] = SENSE_EC;
640 *unitstat = CSW_CE | CSW_DE | CSW_UC;
641 cache_lock(CACHE_DEVBUF);
642 cache_release(CACHE_DEVBUF, o, 0);
643 cache_unlock(CACHE_DEVBUF);
644 return -1;
645 }
646
647 /* Read the block group */
648 rc = read (dev->fd, dev->buf, len);
649 if (rc < len)
650 {
651 /* Handle read error condition */
652 logmsg (_("HHCDA076E error reading blkgrp %d: read error: %s\n"),
653 blkgrp, rc < 0 ? strerror(errno) : "end of file");
654 dev->sense[0] = SENSE_EC;
655 *unitstat = CSW_CE | CSW_DE | CSW_UC;
656 cache_lock(CACHE_DEVBUF);
657 cache_release(CACHE_DEVBUF, o, 0);
658 cache_unlock(CACHE_DEVBUF);
659 return -1;
660 }
661
662 dev->cache = o;
663 dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0);
664 dev->bufcur = blkgrp;
665 dev->bufoff = 0;
666 dev->bufoffhi = fba_blkgrp_len (dev, blkgrp);
667 dev->buflen = fba_blkgrp_len (dev, blkgrp);
668 dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache);
669
670 return 0;
671
672 } /* end function fbadasd_read_blkgrp */
673
674 /*-------------------------------------------------------------------*/
675 /* FBA update block group exit */
676 /*-------------------------------------------------------------------*/
677 static
fbadasd_update_blkgrp(DEVBLK * dev,int blkgrp,int off,BYTE * buf,int len,BYTE * unitstat)678 int fbadasd_update_blkgrp (DEVBLK *dev, int blkgrp, int off,
679 BYTE *buf, int len, BYTE *unitstat)
680 {
681 int rc; /* Return code */
682
683 /* Read the block group */
684 if (blkgrp != dev->bufcur)
685 {
686 rc = (dev->hnd->read) (dev, blkgrp, unitstat);
687 if (rc < 0)
688 {
689 dev->bufcur = dev->cache = -1;
690 return -1;
691 }
692 }
693
694 /* Copy to the device buffer */
695 if (buf) memcpy (dev->buf + off, buf, len);
696
697 /* Update high/low offsets */
698 if (!dev->bufupd || off < dev->bufupdlo)
699 dev->bufupdlo = off;
700 if (off + len > dev-> bufupdhi)
701 dev->bufupdhi = off + len;
702
703 /* Indicate block group has been modified */
704 if (!dev->bufupd)
705 {
706 dev->bufupd = 1;
707 shared_update_notify (dev, blkgrp);
708 }
709
710 return len;
711 } /* end function fbadasd_update_blkgrp */
712
713 /*-------------------------------------------------------------------*/
714 /* Channel program end exit */
715 /*-------------------------------------------------------------------*/
716 static
fbadasd_end(DEVBLK * dev)717 void fbadasd_end (DEVBLK *dev)
718 {
719 BYTE unitstat;
720
721 /* Forces updated buffer to be written */
722 (dev->hnd->read) (dev, -1, &unitstat);
723 }
724
725 /*-------------------------------------------------------------------*/
726 /* Release cache entries */
727 /*-------------------------------------------------------------------*/
fbadasd_purge_cache(int * answer,int ix,int i,void * data)728 int fbadasd_purge_cache (int *answer, int ix, int i, void *data)
729 {
730 U16 devnum; /* Cached device number */
731 int blkgrp; /* Cached block group */
732 DEVBLK *dev = data; /* -> device block */
733
734 UNREFERENCED(answer);
735 FBA_CACHE_GETKEY(i, devnum, blkgrp);
736 if (dev->devnum == devnum)
737 cache_release (ix, i, CACHE_FREEBUF);
738 return 0;
739 }
740
741 /*-------------------------------------------------------------------*/
742 /* Close the device */
743 /*-------------------------------------------------------------------*/
fbadasd_close_device(DEVBLK * dev)744 int fbadasd_close_device ( DEVBLK *dev )
745 {
746 BYTE unitstat;
747
748 /* Forces updated buffer to be written */
749 (dev->hnd->read) (dev, -1, &unitstat);
750
751 /* Free the cache */
752 cache_lock(CACHE_DEVBUF);
753 cache_scan(CACHE_DEVBUF, fbadasd_purge_cache, dev);
754 cache_unlock(CACHE_DEVBUF);
755
756 /* Close the device file */
757 close (dev->fd);
758 dev->fd = -1;
759
760 return 0;
761 } /* end function fbadasd_close_device */
762
763 /*-------------------------------------------------------------------*/
764 /* Return used blocks */
765 /*-------------------------------------------------------------------*/
766 static
fbadasd_used(DEVBLK * dev)767 int fbadasd_used (DEVBLK *dev)
768 {
769 return dev->fbanumblk;
770 }
771
772 /*-------------------------------------------------------------------*/
773 /* Execute a Channel Command Word */
774 /*-------------------------------------------------------------------*/
fbadasd_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)775 void fbadasd_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags,
776 BYTE chained, U16 count, BYTE prevcode, int ccwseq,
777 BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual )
778 {
779 int rc; /* Return code */
780 int num; /* Number of bytes to move */
781 BYTE hexzeroes[512]; /* Bytes for zero fill */
782 int rem; /* Byte count for zero fill */
783 int repcnt; /* Replication count */
784
785 /* Reset extent flag at start of CCW chain */
786 if (chained == 0)
787 dev->fbaxtdef = 0;
788
789 /* Process depending on CCW opcode */
790 switch (code) {
791
792 case 0x02:
793 /*---------------------------------------------------------------*/
794 /* READ IPL */
795 /*---------------------------------------------------------------*/
796 /* Must be first CCW or chained from a previous READ IPL CCW */
797 if (chained && prevcode != 0x02)
798 {
799 dev->sense[0] = SENSE_CR;
800 *unitstat = CSW_CE | CSW_DE | CSW_UC;
801 break;
802 }
803
804 /* Zeroize the file mask and set extent for entire device */
805 dev->fbamask = 0;
806 dev->fbaxblkn = 0;
807 dev->fbaxfirst = 0;
808 dev->fbaxlast = dev->fbanumblk - 1;
809
810 /* Seek to start of block zero */
811 dev->fbarba = dev->fbaorigin * dev->fbablksiz;
812
813 /* Overrun if data chaining */
814 if ((flags & CCW_FLAGS_CD))
815 {
816 dev->sense[0] = SENSE_OR;
817 *unitstat = CSW_CE | CSW_DE | CSW_UC;
818 break;
819 }
820
821 /* Calculate number of bytes to read and set residual count */
822 num = (count < dev->fbablksiz) ? count : dev->fbablksiz;
823 *residual = count - num;
824 if (count < dev->fbablksiz) *more = 1;
825
826 /* Read physical block into channel buffer */
827 rc = fba_read (dev, iobuf, num, unitstat);
828 if (rc < num) break;
829
830 /* Set extent defined flag */
831 dev->fbaxtdef = 1;
832
833 /* Set normal status */
834 *unitstat = CSW_CE | CSW_DE;
835 break;
836
837 case 0x03:
838 /*---------------------------------------------------------------*/
839 /* CONTROL NO-OPERATION */
840 /*---------------------------------------------------------------*/
841 *unitstat = CSW_CE | CSW_DE;
842 break;
843
844 case 0x41:
845 /*---------------------------------------------------------------*/
846 /* WRITE */
847 /*---------------------------------------------------------------*/
848 /* Reject if previous command was not LOCATE */
849 if (prevcode != 0x43)
850 {
851 dev->sense[0] = SENSE_CR;
852 *unitstat = CSW_CE | CSW_DE | CSW_UC;
853 break;
854 }
855
856 /* Reject if locate command did not specify write operation */
857 if ((dev->fbaoper & FBAOPER_CODE) != FBAOPER_WRITE
858 && (dev->fbaoper & FBAOPER_CODE) != FBAOPER_WRTVRFY)
859 {
860 dev->sense[0] = SENSE_CR;
861 *unitstat = CSW_CE | CSW_DE | CSW_UC;
862 break;
863 }
864
865 /* Prepare a block of zeroes for write padding */
866 memset (hexzeroes, 0, sizeof(hexzeroes));
867
868 /* Write physical blocks of data to the device */
869 while (dev->fbalcnum > 0)
870 {
871 /* Exit if data chaining and this CCW is exhausted */
872 if ((flags & CCW_FLAGS_CD) && count == 0)
873 break;
874
875 /* Overrun if data chaining within a physical block */
876 if ((flags & CCW_FLAGS_CD) && count < dev->fbablksiz)
877 {
878 dev->sense[0] = SENSE_OR;
879 *unitstat = CSW_CE | CSW_DE | CSW_UC;
880 break;
881 }
882
883 /* Calculate number of bytes to write */
884 num = (count < dev->fbablksiz) ? count : dev->fbablksiz;
885 if (num < dev->fbablksiz) *more = 1;
886
887 /* Write physical block from channel buffer */
888 if (num > 0)
889 {
890 rc = fba_write (dev, iobuf, num, unitstat);
891 if (rc < num) break;
892 }
893
894 /* Fill remainder of block with zeroes */
895 if (num < dev->fbablksiz)
896 {
897 rem = dev->fbablksiz - num;
898 rc = fba_write (dev, hexzeroes, rem, unitstat);
899 if (rc < rem) break;
900 }
901
902 /* Prepare to write next block */
903 count -= num;
904 iobuf += num;
905 dev->fbalcnum--;
906
907 } /* end while */
908
909 /* Set residual byte count */
910 *residual = count;
911 if (dev->fbalcnum > 0) *more = 1;
912
913 /* Set ending status */
914 *unitstat |= CSW_CE | CSW_DE;
915 break;
916
917 case 0x42:
918 /*---------------------------------------------------------------*/
919 /* READ */
920 /*---------------------------------------------------------------*/
921 /* Reject if previous command was not LOCATE or READ IPL */
922 if (prevcode != 0x43 && prevcode != 0x02)
923 {
924 dev->sense[0] = SENSE_CR;
925 *unitstat = CSW_CE | CSW_DE | CSW_UC;
926 break;
927 }
928
929 /* Reject if locate command did not specify read operation */
930 if (prevcode != 0x02
931 && (dev->fbaoper & FBAOPER_CODE) != FBAOPER_READ
932 && (dev->fbaoper & FBAOPER_CODE) != FBAOPER_READREP)
933 {
934 dev->sense[0] = SENSE_CR;
935 *unitstat = CSW_CE | CSW_DE | CSW_UC;
936 break;
937 }
938
939 /* Read physical blocks of data from device */
940 while (dev->fbalcnum > 0 && count > 0)
941 {
942 /* Overrun if data chaining within a physical block */
943 if ((flags & CCW_FLAGS_CD) && count < dev->fbablksiz)
944 {
945 dev->sense[0] = SENSE_OR;
946 *unitstat = CSW_CE | CSW_DE | CSW_UC;
947 break;
948 }
949
950 /* Calculate number of bytes to read */
951 num = (count < dev->fbablksiz) ? count : dev->fbablksiz;
952 if (num < dev->fbablksiz) *more = 1;
953
954 /* Read physical block into channel buffer */
955 rc = fba_read (dev, iobuf, num, unitstat);
956 if (rc < num) break;
957
958 /* Prepare to read next block */
959 count -= num;
960 iobuf += num;
961 dev->fbalcnum--;
962
963 } /* end while */
964
965 /* Set residual byte count */
966 *residual = count;
967 if (dev->fbalcnum > 0) *more = 1;
968
969 /* Set ending status */
970 *unitstat |= CSW_CE | CSW_DE;
971
972 break;
973
974 case 0x43:
975 /*---------------------------------------------------------------*/
976 /* LOCATE */
977 /*---------------------------------------------------------------*/
978 /* Calculate residual byte count */
979 num = (count < 8) ? count : 8;
980 *residual = count - num;
981
982 /* Control information length must be at least 8 bytes */
983 if (count < 8)
984 {
985 dev->sense[0] = SENSE_CR;
986 *unitstat = CSW_CE | CSW_DE | CSW_UC;
987 break;
988 }
989
990 /* LOCATE must be preceded by DEFINE EXTENT or READ IPL */
991 if (dev->fbaxtdef == 0)
992 {
993 dev->sense[0] = SENSE_CR;
994 *unitstat = CSW_CE | CSW_DE | CSW_UC;
995 break;
996 }
997
998 /* Save and validate the operation byte */
999 dev->fbaoper = iobuf[0];
1000 if (dev->fbaoper & FBAOPER_RESV)
1001 {
1002 dev->sense[0] = SENSE_CR;
1003 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1004 break;
1005 }
1006
1007 /* Validate and process operation code */
1008 if ((dev->fbaoper & FBAOPER_CODE) == FBAOPER_WRITE
1009 || (dev->fbaoper & FBAOPER_CODE) == FBAOPER_WRTVRFY)
1010 {
1011 /* Reject command if file mask inhibits all writes */
1012 if ((dev->fbamask & FBAMASK_CTL) == FBAMASK_CTL_INHWRT)
1013 {
1014 dev->sense[0] = SENSE_CR;
1015 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1016 break;
1017 }
1018 }
1019 else if ((dev->fbaoper & FBAOPER_CODE) == FBAOPER_READ
1020 || (dev->fbaoper & FBAOPER_CODE) == FBAOPER_READREP)
1021 {
1022 }
1023 else if ((dev->fbaoper & FBAOPER_CODE) == FBAOPER_FMTDEFC)
1024 {
1025 /* Reject command if file mask inhibits format writes */
1026 if ((dev->fbamask & FBAMASK_CTL) == FBAMASK_CTL_INHFMT)
1027 {
1028 dev->sense[0] = SENSE_CR;
1029 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1030 break;
1031 }
1032 }
1033 else /* Operation code is invalid */
1034 {
1035 dev->sense[0] = SENSE_CR;
1036 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1037 break;
1038 }
1039
1040 /* Byte 1 contains the replication count */
1041 repcnt = iobuf[1];
1042
1043 /* Bytes 2-3 contain the block count */
1044 dev->fbalcnum = fetch_hw(iobuf + 2);
1045
1046 /* Bytes 4-7 contain the displacement of the first block
1047 relative to the start of the dataset */
1048 dev->fbalcblk = fetch_fw(iobuf + 4);
1049
1050 /* Verify that the block count is non-zero, and that
1051 the starting and ending blocks fall within the extent */
1052 if ( dev->fbalcnum == 0
1053 || dev->fbalcnum > dev->fbaxlast + 1
1054 || dev->fbalcblk < dev->fbaxfirst
1055 || dev->fbalcblk > dev->fbaxlast + 1 - dev->fbalcnum)
1056 {
1057 dev->sense[0] = SENSE_CR;
1058 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1059 break;
1060 }
1061
1062 /* For replicated data, verify that the replication count
1063 is non-zero and is a multiple of the block count */
1064 if ((dev->fbaoper & FBAOPER_CODE) == FBAOPER_READREP)
1065 {
1066 if (repcnt == 0 || repcnt % dev->fbalcnum != 0)
1067 {
1068 dev->sense[0] = SENSE_CR;
1069 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1070 break;
1071 }
1072 }
1073
1074 /* Position device to start of block */
1075 dev->fbarba = (dev->fbaorigin
1076 + dev->fbaxblkn
1077 + dev->fbalcblk - dev->fbaxfirst
1078 ) * dev->fbablksiz;
1079
1080 logdevtr (dev, _("HHCDA077I Positioning to %8.8" I64_FMT "X (%" I64_FMT "u)\n"),
1081 (long long unsigned int)dev->fbarba, (long long unsigned int)dev->fbarba);
1082
1083 /* Return normal status */
1084 *unitstat = CSW_CE | CSW_DE;
1085 break;
1086
1087 case 0x63:
1088 /*---------------------------------------------------------------*/
1089 /* DEFINE EXTENT */
1090 /*---------------------------------------------------------------*/
1091 /* Calculate residual byte count */
1092 num = (count < 16) ? count : 16;
1093 *residual = count - num;
1094
1095 /* Control information length must be at least 16 bytes */
1096 if (count < 16)
1097 {
1098 logmsg(_("HHCDA078E define extent data too short: %d bytes\n"),
1099 count);
1100 dev->sense[0] = SENSE_CR;
1101 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1102 break;
1103 }
1104
1105 /* Reject if extent previously defined in this CCW chain */
1106 if (dev->fbaxtdef)
1107 {
1108 logmsg(_("HHCDA079E second define extent in chain\n"));
1109 dev->sense[0] = SENSE_CR;
1110 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1111 break;
1112 }
1113
1114 /* Save and validate the file mask */
1115 dev->fbamask = iobuf[0];
1116 if ((dev->fbamask & (FBAMASK_RESV | FBAMASK_CE))
1117 || (dev->fbamask & FBAMASK_CTL) == FBAMASK_CTL_RESV)
1118 {
1119 logmsg(_("HHCDA080E invalid file mask %2.2X\n"),
1120 dev->fbamask);
1121 dev->sense[0] = SENSE_CR;
1122 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1123 break;
1124 }
1125
1126 // VM/ESA sends 0x00000200 0x00000000 0x00000000 0x0001404F
1127 // /* Verify that bytes 1-3 are zeroes */
1128 // if (iobuf[1] != 0 || iobuf[2] != 0 || iobuf[3] != 0)
1129 // {
1130 // logmsg(_("fbadasd: invalid reserved bytes %2.2X %2.2X %2.2X\n"),
1131 // iobuf[1], iobuf[2], iobuf[3]);
1132 // dev->sense[0] = SENSE_CR;
1133 // *unitstat = CSW_CE | CSW_DE | CSW_UC;
1134 // break;
1135 // }
1136
1137 /* Bytes 4-7 contain the block number of the first block
1138 of the extent relative to the start of the device */
1139 dev->fbaxblkn = fetch_fw(iobuf + 4);
1140
1141 /* Bytes 8-11 contain the block number of the first block
1142 of the extent relative to the start of the dataset */
1143 dev->fbaxfirst = fetch_fw(iobuf + 8);
1144
1145 /* Bytes 12-15 contain the block number of the last block
1146 of the extent relative to the start of the dataset */
1147 dev->fbaxlast = fetch_fw(iobuf + 12);
1148
1149 /* Validate the extent description by checking that the
1150 ending block is not less than the starting block and
1151 that the ending block does not exceed the device size */
1152 if (dev->fbaxlast < dev->fbaxfirst
1153 || dev->fbaxblkn > (U32)dev->fbanumblk
1154 || dev->fbaxlast - dev->fbaxfirst >= dev->fbanumblk - dev->fbaxblkn)
1155 {
1156 logmsg(_("HHCDA081E invalid extent: first block %d, last block %d,\n"),
1157 dev->fbaxfirst, dev->fbaxlast);
1158 logmsg(_(" numblks %d, device size %d\n"),
1159 dev->fbaxblkn, dev->fbanumblk);
1160 dev->sense[0] = SENSE_CR;
1161 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1162 break;
1163 }
1164
1165 /* Set extent defined flag and return normal status */
1166 dev->fbaxtdef = 1;
1167 *unitstat = CSW_CE | CSW_DE;
1168 break;
1169
1170 case 0x64:
1171 /*---------------------------------------------------------------*/
1172 /* READ DEVICE CHARACTERISTICS */
1173 /*---------------------------------------------------------------*/
1174 /* Calculate residual byte count */
1175 num = (count < dev->numdevchar) ? count : dev->numdevchar;
1176 *residual = count - num;
1177 if (count < dev->numdevchar) *more = 1;
1178
1179 /* Copy device characteristics bytes to channel buffer */
1180 memcpy (iobuf, dev->devchar, num);
1181
1182 *unitstat = CSW_CE | CSW_DE;
1183 break;
1184
1185 case 0x94:
1186 /*---------------------------------------------------------------*/
1187 /* DEVICE RELEASE */
1188 /*---------------------------------------------------------------*/
1189 /* Reject if extent previously defined in this CCW chain */
1190 if (dev->fbaxtdef)
1191 {
1192 dev->sense[0] = SENSE_CR;
1193 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1194 break;
1195 }
1196
1197 if (dev->hnd->release) (dev->hnd->release) (dev);
1198
1199 obtain_lock (&dev->lock);
1200 dev->reserved = 0;
1201 release_lock (&dev->lock);
1202
1203 /* Return sense information */
1204 goto sense;
1205
1206 case 0xB4:
1207 /*---------------------------------------------------------------*/
1208 /* DEVICE RESERVE */
1209 /*---------------------------------------------------------------*/
1210 /* Reject if extent previously defined in this CCW chain */
1211 if (dev->fbaxtdef)
1212 {
1213 dev->sense[0] = SENSE_CR;
1214 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1215 break;
1216 }
1217
1218 /* Reserve device to the ID of the active channel program */
1219
1220 obtain_lock (&dev->lock);
1221 dev->reserved = 1;
1222 release_lock (&dev->lock);
1223
1224 if (dev->hnd->reserve) (dev->hnd->reserve) (dev);
1225
1226 /* Return sense information */
1227 goto sense;
1228
1229 case 0x14:
1230 /*---------------------------------------------------------------*/
1231 /* UNCONDITIONAL RESERVE */
1232 /*---------------------------------------------------------------*/
1233 /* Reject if this is not the first CCW in the chain */
1234 if (ccwseq > 0)
1235 {
1236 dev->sense[0] = SENSE_CR;
1237 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1238 break;
1239 }
1240
1241 /* Reserve device to the ID of the active channel program */
1242
1243 obtain_lock (&dev->lock);
1244 dev->reserved = 1;
1245 release_lock (&dev->lock);
1246
1247 if (dev->hnd->reserve) (dev->hnd->reserve) (dev);
1248
1249 /* Return sense information */
1250 goto sense;
1251
1252 case 0x04:
1253 /*---------------------------------------------------------------*/
1254 /* SENSE */
1255 /*---------------------------------------------------------------*/
1256 sense:
1257 /* Calculate residual byte count */
1258 num = (count < dev->numsense) ? count : dev->numsense;
1259 *residual = count - num;
1260 if (count < dev->numsense) *more = 1;
1261
1262 /* Copy device sense bytes to channel I/O buffer */
1263 memcpy (iobuf, dev->sense, num);
1264
1265 /* Clear the device sense bytes */
1266 memset (dev->sense, 0, sizeof(dev->sense));
1267
1268 /* Return unit status */
1269 *unitstat = CSW_CE | CSW_DE;
1270 break;
1271
1272 case 0xE4:
1273 /*---------------------------------------------------------------*/
1274 /* SENSE ID */
1275 /*---------------------------------------------------------------*/
1276 /* Calculate residual byte count */
1277 num = (count < dev->numdevid) ? count : dev->numdevid;
1278 *residual = count - num;
1279 if (count < dev->numdevid) *more = 1;
1280
1281 /* Copy device identifier bytes to channel I/O buffer */
1282 memcpy (iobuf, dev->devid, num);
1283
1284 /* Return unit status */
1285 *unitstat = CSW_CE | CSW_DE;
1286 break;
1287
1288 case 0xA4:
1289 /*---------------------------------------------------------------*/
1290 /* READ AND RESET BUFFERED LOG */
1291 /*---------------------------------------------------------------*/
1292 /* Calculate residual byte count */
1293 num = (count < 24) ? count : 24;
1294 *residual = count - num;
1295 if (count < 24) *more = 1;
1296
1297 /* Copy device identifier bytes to channel I/O buffer */
1298 memset (iobuf, 0, num);
1299
1300 /* Return unit status */
1301 *unitstat = CSW_CE | CSW_DE;
1302 break;
1303
1304 default:
1305 /*---------------------------------------------------------------*/
1306 /* INVALID OPERATION */
1307 /*---------------------------------------------------------------*/
1308 /* Set command reject sense byte, and unit check status */
1309 dev->sense[0] = SENSE_CR;
1310 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1311
1312 } /* end switch(code) */
1313
1314 } /* end function fbadasd_execute_ccw */
1315
1316 /*-------------------------------------------------------------------*/
1317 /* Read Standard Block (used by Diagnose instructions) */
1318 /*-------------------------------------------------------------------*/
fbadasd_read_block(DEVBLK * dev,int blknum,int blksize,int blkfactor,BYTE * iobuf,BYTE * unitstat,U16 * residual)1319 DLL_EXPORT void fbadasd_read_block
1320 ( DEVBLK *dev, int blknum, int blksize, int blkfactor,
1321 BYTE *iobuf, BYTE *unitstat, U16 *residual )
1322 {
1323 int rc; /* Return code */
1324 int sector; /* First sector being read */
1325
1326 /* Unit check if block number is invalid */
1327 sector = blknum * blkfactor;
1328 if (sector >= dev->fbanumblk)
1329 {
1330 dev->sense[0] = SENSE_CR;
1331 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1332 return;
1333 }
1334
1335 /* Seek to start of desired block */
1336 dev->fbarba = ( dev->fbaorigin + sector ) * dev->fbablksiz;
1337
1338 /* Read block into I/O buffer */
1339 rc = fba_read (dev, iobuf, blksize, unitstat);
1340 if (rc < blksize)
1341 {
1342 dev->sense[0] = SENSE_CR;
1343 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1344 return;
1345 }
1346
1347 /* Return unit status and residual byte count */
1348 *unitstat = CSW_CE | CSW_DE;
1349 *residual = 0;
1350
1351 } /* end function fbadasd_read_block */
1352
1353 /*-------------------------------------------------------------------*/
1354 /* Write Standard Block (used by Diagnose instructions) */
1355 /*-------------------------------------------------------------------*/
fbadasd_write_block(DEVBLK * dev,int blknum,int blksize,int blkfactor,BYTE * iobuf,BYTE * unitstat,U16 * residual)1356 DLL_EXPORT void fbadasd_write_block (
1357 DEVBLK *dev, int blknum, int blksize, int blkfactor,
1358 BYTE *iobuf, BYTE *unitstat, U16 *residual )
1359 {
1360 int rc; /* Return code from write function */
1361 int sector; /* First sector being read */
1362 #if 0
1363 U64 rba; /* Large file size offset */
1364 #endif
1365
1366 /* Unit check if block number is invalid */
1367 sector = blknum * blkfactor;
1368 if (sector >= dev->fbanumblk || sector < 0 )
1369 {
1370 dev->sense[0] = SENSE_CR;
1371 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1372 return;
1373 }
1374
1375 /* Seek to start of desired block */
1376 dev->fbarba = (off_t)(( dev->fbaorigin + sector ) * dev->fbablksiz);
1377
1378 /* Read block into I/O buffer */
1379 rc = fba_write (dev, iobuf, blksize, unitstat);
1380 if (rc < blksize)
1381 {
1382 dev->sense[0] = SENSE_CR;
1383 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1384 return;
1385 }
1386
1387 /* Return unit status and residual byte count */
1388 *unitstat = CSW_CE | CSW_DE;
1389 *residual = 0;
1390
1391 } /* end function fbadasd_write_block */
1392
1393 /* Deprecated: Will be replaced by fbadasd_read/write_block functions */
1394 /*-------------------------------------------------------------------*/
1395 /* Synchronous Fixed Block I/O (used by Diagnose instruction) */
1396 /*-------------------------------------------------------------------*/
fbadasd_syncblk_io(DEVBLK * dev,BYTE type,int blknum,int blksize,BYTE * iobuf,BYTE * unitstat,U16 * residual)1397 DLL_EXPORT void fbadasd_syncblk_io ( DEVBLK *dev, BYTE type, int blknum,
1398 int blksize, BYTE *iobuf, BYTE *unitstat, U16 *residual )
1399 {
1400 int rc; /* Return code */
1401 int blkfactor; /* Number of device blocks
1402 per logical block */
1403
1404 /* Calculate the blocking factor */
1405 blkfactor = blksize / dev->fbablksiz;
1406
1407 /* Unit check if block number is invalid */
1408 if (blknum * blkfactor >= dev->fbanumblk)
1409 {
1410 dev->sense[0] = SENSE_CR;
1411 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1412 return;
1413 }
1414
1415 /* Seek to start of desired block */
1416 dev->fbarba = dev->fbaorigin * dev->fbablksiz;
1417
1418 /* Process depending on operation type */
1419 switch (type) {
1420
1421 case 0x01:
1422 /* Write block from I/O buffer */
1423 rc = fba_write (dev, iobuf, blksize, unitstat);
1424 if (rc < blksize) return;
1425 break;
1426
1427 case 0x02:
1428 /* Read block into I/O buffer */
1429 rc = fba_read (dev, iobuf, blksize, unitstat);
1430 if (rc < blksize) return;
1431 break;
1432
1433 } /* end switch(type) */
1434
1435 /* Return unit status and residual byte count */
1436 *unitstat = CSW_CE | CSW_DE;
1437 *residual = 0;
1438
1439 } /* end function fbadasd_syncblk_io */
1440
1441 /*-------------------------------------------------------------------*/
1442 /* Hercules suspend/resume text unit key values */
1443 /*-------------------------------------------------------------------*/
1444 #define SR_DEV_FBA_BUFCUR ( SR_DEV_FBA | 0x001 )
1445 #define SR_DEV_FBA_BUFOFF ( SR_DEV_FBA | 0x002 )
1446 #define SR_DEV_FBA_ORIGIN ( SR_DEV_FBA | 0x003 )
1447 #define SR_DEV_FBA_NUMBLK ( SR_DEV_FBA | 0x004 )
1448 #define SR_DEV_FBA_RBA ( SR_DEV_FBA | 0x005 )
1449 #define SR_DEV_FBA_END ( SR_DEV_FBA | 0x006 )
1450 #define SR_DEV_FBA_DXBLKN ( SR_DEV_FBA | 0x007 )
1451 #define SR_DEV_FBA_DXFIRST ( SR_DEV_FBA | 0x008 )
1452 #define SR_DEV_FBA_DXLAST ( SR_DEV_FBA | 0x009 )
1453 #define SR_DEV_FBA_LCBLK ( SR_DEV_FBA | 0x00a )
1454 #define SR_DEV_FBA_LCNUM ( SR_DEV_FBA | 0x00b )
1455 #define SR_DEV_FBA_BLKSIZ ( SR_DEV_FBA | 0x00c )
1456 #define SR_DEV_FBA_XTDEF ( SR_DEV_FBA | 0x00d )
1457 #define SR_DEV_FBA_OPER ( SR_DEV_FBA | 0x00e )
1458 #define SR_DEV_FBA_MASK ( SR_DEV_FBA | 0x00f )
1459
1460 /*-------------------------------------------------------------------*/
1461 /* Hercules suspend */
1462 /*-------------------------------------------------------------------*/
fbadasd_hsuspend(DEVBLK * dev,void * file)1463 int fbadasd_hsuspend(DEVBLK *dev, void *file) {
1464 if (dev->bufcur >= 0)
1465 {
1466 SR_WRITE_VALUE(file, SR_DEV_FBA_BUFCUR, dev->bufcur, sizeof(dev->bufcur));
1467 SR_WRITE_VALUE(file, SR_DEV_FBA_BUFOFF, dev->bufoff, sizeof(dev->bufoff));
1468 }
1469 SR_WRITE_VALUE(file, SR_DEV_FBA_ORIGIN, dev->fbaorigin, sizeof(dev->fbaorigin));
1470 SR_WRITE_VALUE(file, SR_DEV_FBA_NUMBLK, dev->fbanumblk, sizeof(dev->fbanumblk));
1471 SR_WRITE_VALUE(file, SR_DEV_FBA_RBA, dev->fbarba, sizeof(dev->fbarba));
1472 SR_WRITE_VALUE(file, SR_DEV_FBA_END, dev->fbaend, sizeof(dev->fbaend));
1473 SR_WRITE_VALUE(file, SR_DEV_FBA_DXBLKN, dev->fbaxblkn, sizeof(dev->fbaxblkn));
1474 SR_WRITE_VALUE(file, SR_DEV_FBA_DXFIRST, dev->fbaxfirst, sizeof(dev->fbaxfirst));
1475 SR_WRITE_VALUE(file, SR_DEV_FBA_DXLAST, dev->fbaxlast, sizeof(dev->fbaxlast));
1476 SR_WRITE_VALUE(file, SR_DEV_FBA_LCBLK, dev->fbalcblk, sizeof(dev->fbalcblk));
1477 SR_WRITE_VALUE(file, SR_DEV_FBA_LCNUM, dev->fbalcnum, sizeof(dev->fbalcnum));
1478 SR_WRITE_VALUE(file, SR_DEV_FBA_BLKSIZ, dev->fbablksiz, sizeof(dev->fbablksiz));
1479 SR_WRITE_VALUE(file, SR_DEV_FBA_XTDEF, dev->fbaxtdef, 1);
1480 SR_WRITE_VALUE(file, SR_DEV_FBA_OPER, dev->fbaoper, sizeof(dev->fbaoper));
1481 SR_WRITE_VALUE(file, SR_DEV_FBA_MASK, dev->fbamask, sizeof(dev->fbamask));
1482 return 0;
1483 }
1484
1485 /*-------------------------------------------------------------------*/
1486 /* Hercules resume */
1487 /*-------------------------------------------------------------------*/
fbadasd_hresume(DEVBLK * dev,void * file)1488 int fbadasd_hresume(DEVBLK *dev, void *file)
1489 {
1490 int rc;
1491 size_t key, len;
1492 BYTE byte;
1493
1494 do {
1495 SR_READ_HDR(file, key, len);
1496 switch (key) {
1497 case SR_DEV_FBA_BUFCUR:
1498 SR_READ_VALUE(file, len, &rc, sizeof(rc));
1499 rc = (dev->hnd->read) ? (dev->hnd->read)(dev, rc, &byte) : -1;
1500 if ((int)rc < 0) return -1;
1501 break;
1502 case SR_DEV_FBA_BUFOFF:
1503 SR_READ_VALUE(file, len, &dev->bufoff, sizeof(dev->bufoff));
1504 break;
1505 case SR_DEV_FBA_ORIGIN:
1506 SR_READ_VALUE(file, len, &rc, sizeof(rc));
1507 if ((off_t)rc != dev->fbaorigin)
1508 {
1509 logmsg(_("HHCDA901E %4.4x FBA origin mismatch: %d, expected %d,\n"),
1510 rc, dev->fbaorigin);
1511 return -1;
1512 }
1513 break;
1514 case SR_DEV_FBA_NUMBLK:
1515 SR_READ_VALUE(file, len, &rc, sizeof(rc));
1516 if ((int)rc != dev->fbanumblk)
1517 {
1518 logmsg(_("HHCDA902E %4.4x FBA numblk mismatch: %d, expected %d,\n"),
1519 rc, dev->fbanumblk);
1520 return -1;
1521 }
1522 break;
1523 case SR_DEV_FBA_RBA:
1524 SR_READ_VALUE(file, len, &dev->fbarba, sizeof(dev->fbarba));
1525 break;
1526 case SR_DEV_FBA_END:
1527 SR_READ_VALUE(file, len, &dev->fbaend, sizeof(dev->fbaend));
1528 break;
1529 case SR_DEV_FBA_DXBLKN:
1530 SR_READ_VALUE(file, len, &dev->fbaxblkn, sizeof(dev->fbaxblkn));
1531 break;
1532 case SR_DEV_FBA_DXFIRST:
1533 SR_READ_VALUE(file, len, &dev->fbaxfirst, sizeof(dev->fbaxfirst));
1534 break;
1535 case SR_DEV_FBA_DXLAST:
1536 SR_READ_VALUE(file, len, &dev->fbaxlast, sizeof(dev->fbaxlast));
1537 break;
1538 case SR_DEV_FBA_LCBLK:
1539 SR_READ_VALUE(file, len, &dev->fbalcblk, sizeof(dev->fbalcblk));
1540 break;
1541 case SR_DEV_FBA_LCNUM:
1542 SR_READ_VALUE(file, len, &dev->fbalcnum, sizeof(dev->fbalcnum));
1543 break;
1544 case SR_DEV_FBA_BLKSIZ:
1545 SR_READ_VALUE(file, len, &rc, sizeof(rc));
1546 if ((int)rc != dev->fbablksiz)
1547 {
1548 logmsg(_("HHCDA903E %4.4x FBA blksiz mismatch: %d, expected %d,\n"),
1549 rc, dev->fbablksiz);
1550 return -1;
1551 }
1552 break;
1553 case SR_DEV_FBA_XTDEF:
1554 SR_READ_VALUE(file, len, &rc, sizeof(rc));
1555 dev->fbaxtdef = rc;
1556 break;
1557 case SR_DEV_FBA_OPER:
1558 SR_READ_VALUE(file, len, &dev->fbaoper, sizeof(dev->fbaoper));
1559 break;
1560 case SR_DEV_FBA_MASK:
1561 SR_READ_VALUE(file, len, &dev->fbamask, sizeof(dev->fbamask));
1562 break;
1563 default:
1564 SR_READ_SKIP(file, len);
1565 break;
1566 } /* switch (key) */
1567 } while ((key & SR_DEV_MASK) == SR_DEV_FBA);
1568 return 0;
1569 }
1570
1571 DLL_EXPORT DEVHND fbadasd_device_hndinfo = {
1572 &fbadasd_init_handler, /* Device Initialisation */
1573 &fbadasd_execute_ccw, /* Device CCW execute */
1574 &fbadasd_close_device, /* Device Close */
1575 &fbadasd_query_device, /* Device Query */
1576 NULL, /* Device Start channel pgm */
1577 &fbadasd_end, /* Device End channel pgm */
1578 NULL, /* Device Resume channel pgm */
1579 &fbadasd_end, /* Device Suspend channel pgm */
1580 &fbadasd_read_blkgrp, /* Device Read */
1581 &fbadasd_update_blkgrp, /* Device Write */
1582 &fbadasd_used, /* Device Query used */
1583 NULL, /* Device Reserve */
1584 NULL, /* Device Release */
1585 NULL, /* Device Attention */
1586 NULL, /* Immediate CCW Codes */
1587 NULL, /* Signal Adapter Input */
1588 NULL, /* Signal Adapter Ouput */
1589 &fbadasd_hsuspend, /* Hercules suspend */
1590 &fbadasd_hresume /* Hercules resume */
1591 };
1592