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