1 /* SCSITAPE.C   (c) Copyright "Fish" (David B. Trout), 2005-2012     */
2 /*              Hercules SCSI tape handling module                   */
3 
4 // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under
5 // the Q Public License (http://www.hercules-390.org/herclic.html)
6 // as modifications to Hercules.
7 
8 /*-------------------------------------------------------------------*/
9 /* This module contains only the support for SCSI tapes. Please see  */
10 /* the 'tapedev.c' (and possibly other) source module(s) for infor-  */
11 /* mation regarding other supported emulated tape/media formats.     */
12 /*-------------------------------------------------------------------*/
13 
14 /*-------------------------------------------------------------------*/
15 /* Messages issued by this module are prefixed HHCTA3nn              */
16 /*-------------------------------------------------------------------*/
17 
18 #include "hstdinc.h"
19 #include "hercules.h"
20 #include "scsitape.h"
21 
22 #if defined(OPTION_SCSI_TAPE)
23 
24 //#define  ENABLE_TRACING_STMTS     // (Fish: DEBUGGING)
25 
26 #ifdef ENABLE_TRACING_STMTS
27   #if !defined(DEBUG)
28     #warning DEBUG required for ENABLE_TRACING_STMTS
29   #endif
30   // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h)
31 #else
32   #undef  TRACE
33   #define TRACE       1 ? ((void)0) : logmsg
34   #undef  ASSERT
35   #define ASSERT(a)
36   #undef  VERIFY
37   #define VERIFY(a)   ((void)(a))
38 #endif
39 
40 // (the following is just a [slightly] shorter name for our own internal use)
41 #define SLOW_UPDATE_STATUS_TIMEOUT  MAX_NORMAL_SCSI_DRIVE_QUERY_RESPONSE_TIMEOUT_USECS
42 #define MAX_GSTAT_FREQ_USECS        1000000   // (once per second max)
43 
44 /*-------------------------------------------------------------------*/
45 /*                 Open a SCSI tape device                           */
46 /*                                                                   */
47 /* If successful, the file descriptor is stored in the device block  */
48 /* and the return value is zero.  Otherwise the return value is -1.  */
49 /*                                                                   */
50 /* Note that not having a tape mounted is a non-fatal error (rc==0)) */
51 /*                                                                   */
52 /* If the status indicates the tape is not mounted or a good status  */
53 /* cannot otherwise be obtained, the file descriptor is CLOSED but   */
54 /* THE RETURN CODE IS STILL == 0 !!!!                                */
55 /*                                                                   */
56 /*                       ** WARNING! **                              */
57 /*                                                                   */
58 /* The caller MUST check for a valid (non-negative) file descriptor  */
59 /* before trying to use it if this function returns 0 == success!!   */
60 /*                                                                   */
61 /* A success == 0 return means the device filename CAN be opened,    */
62 /* but not necessarily that the file can be used! If the file cannot */
63 /* be used (i.e. no tape mounted), the file is CLOSED but the return */
64 /* code is still == 0.                                               */
65 /*                                                                   */
66 /* The return code is -1 ONLY when the filename itself is invalid    */
67 /* and the device file thus cannot even be opened.                   */
68 /*                                                                   */
69 /*-------------------------------------------------------------------*/
open_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)70 int open_scsitape (DEVBLK *dev, BYTE *unitstat, BYTE code)
71 {
72 int rc;
73 
74     /* Is an open for this device already in progress? */
75     if (dev->stape_mntdrq.link.Flink)
76     {
77         /* Yes. Device is good but no tape is mounted (yet) */
78         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
79         return 0; // (quick exit; in progress == open success)
80     }
81 
82     ASSERT( dev->fd < 0 );  // (sanity check)
83     dev->fd = -1;
84     dev->sstat = GMT_DR_OPEN( -1 );
85 
86     /* Open the SCSI tape device */
87     dev->readonly = 0;
88     rc = open_tape (dev->filename, O_RDWR | O_BINARY | O_NONBLOCK);
89     if (rc < 0 && EROFS == errno )
90     {
91         dev->readonly = 1;
92         rc = open_tape (dev->filename, O_RDONLY | O_BINARY | O_NONBLOCK);
93     }
94 
95     /* Check for successful open */
96     if (rc < 0)
97     {
98         logmsg (_("HHCTA324E Error opening %u:%4.4X=%s; errno=%d: %s\n"),
99                 SSID_TO_LCSS(dev->ssid), dev->devnum,
100                 dev->filename, errno, strerror(errno));
101         build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code);
102         return -1; // (FATAL error; device cannot be opened)
103     }
104 
105     define_BOT_pos( dev );  // (always after successful open)
106 
107     /* Store the file descriptor in the device block */
108     dev->fd = rc;
109 
110     /* Obtain the initial tape device/media status information */
111     /* and start the mount-monitoring thread if option enabled */
112     int_scsi_status_update( dev, 0 );
113 
114     /* Asynchronous open now in progress? */
115     if (dev->stape_mntdrq.link.Flink)
116     {
117         /* Yes. Device is good but no tape is mounted (yet) */
118         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
119         return 0; // (quick exit; in progress == open success)
120     }
121 
122     /* Finish up the open process... */
123     if ( STS_NOT_MOUNTED( dev ) )
124     {
125         /* Intervention required if no tape is currently mounted.
126            Note: we return "success" because the filename is good
127            (device CAN be opened) but close the file descriptor
128            since there's no tape currently mounted on the drive.*/
129 #if !defined( _MSVC_ )
130         int fd = dev->fd;
131         dev->fd = -1;
132         close_tape( fd );
133 #endif // !_MSVC_
134         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
135         return 0; // (because device file IS valid and CAN be opened)
136     }
137 
138     /* Set variable length block processing to complete the open */
139     if ( finish_scsitape_open( dev, unitstat, code ) != 0 )
140     {
141         /* We cannot use this device; fail the open.
142            'finish_scsitape_open' has already issued
143            the error message and closed the device. */
144         return -1;  // (open failure)
145     }
146     return 0;       // (open success)
147 
148 } /* end function open_scsitape */
149 
150 /*-------------------------------------------------------------------*/
151 /*  Finish SCSI Tape open:  sets variable length block i/o mode...   */
152 /*  Returns 0 == success, -1 = failure.                              */
153 /*-------------------------------------------------------------------*/
154 /*  THIS FUNCTION IS AN INTEGRAL PART OF TAPE OPEN PROCESSING!       */
155 /*  If this function fails then the overall tape device open fails!  */
156 /*-------------------------------------------------------------------*/
finish_scsitape_open(DEVBLK * dev,BYTE * unitstat,BYTE code)157 int finish_scsitape_open( DEVBLK *dev, BYTE *unitstat, BYTE code )
158 {
159 int             rc;                     /* Return code               */
160 int             oflags;                 /* re-open flags             */
161 struct mtop     opblk;                  /* Area for MTIOCTOP ioctl   */
162 
163     /* Switch drive over to BLOCKING-mode i/o... */
164 
165     close_tape( dev->fd );
166     oflags = O_BINARY | (dev->readonly ? O_RDONLY : O_RDWR);
167     VERIFY( (dev->fd = open_tape (dev->filename, oflags)) > 0);
168 
169     /* Since a tape was just mounted, reset the blockid back to zero */
170 
171     dev->blockid = 0;
172     dev->fenced = 0;
173 
174     /* Set the tape device to process variable length blocks */
175 
176     if (!STS_WR_PROT( dev ))
177     {
178         opblk.mt_op = MTSETBLK;
179         opblk.mt_count = 0;
180 
181         rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk);
182 
183         if (rc < 0)
184         {
185             /* Device cannot be used; fail the open */
186             int save_errno = errno;
187             rc = dev->fd;
188             dev->fd = -1;
189             close_tape( rc );
190             errno = save_errno;
191             logmsg (_("HHCTA330E Error setting attributes for %u:%4.4X=%s; errno=%d: %s\n"),
192                     SSID_TO_LCSS(dev->ssid), dev->devnum,
193                     dev->filename, errno, strerror(errno));
194             build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code);
195             return -1; /* (fatal error) */
196         }
197     }
198 
199 #if defined( HAVE_DECL_MTEWARN ) && HAVE_DECL_MTEWARN
200 
201     // Try to request EOM/EOT (end-of-media/tape) early-warning
202 
203     // Note: if it fails, oh well. There's no need to scare the
204     // user with a warning message. We'll either get the warning
205     // or we won't. Either way there's nothing we can do about it.
206     // We did the best we could.
207 
208     if (!STS_WR_PROT( dev ))
209     {
210         opblk.mt_op = MTEWARN;
211         opblk.mt_count = dev->eotmargin;
212 
213         ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk);
214 
215         // (ignore any error; it either worked or it didn't)
216     }
217 
218 #endif // defined( HAVE_DECL_MTEWARN ) && HAVE_DECL_MTEWARN
219 
220     return 0;  /* (success) */
221 
222 } /* end function finish_scsitape_open */
223 
224 /*-------------------------------------------------------------------*/
225 /* Close SCSI tape device file                                       */
226 /*-------------------------------------------------------------------*/
close_scsitape(DEVBLK * dev)227 void close_scsitape(DEVBLK *dev)
228 {
229     int rc = 0;
230 
231     obtain_lock( &sysblk.stape_lock );
232 
233     // Remove drive from SCSIMOUNT thread's work queue...
234 
235     if (dev->stape_mntdrq.link.Flink) {
236         RemoveListEntry( &dev->stape_mntdrq.link );
237         InitializeListLink( &dev->stape_mntdrq.link );
238     }
239 
240     // Remove drive from the STATUS thread's work queue...
241 
242     if (dev->stape_statrq.link.Flink) {
243         RemoveListEntry( &dev->stape_statrq.link );
244         InitializeListLink( &dev->stape_statrq.link );
245     }
246 
247     // Close the file if it's open...
248     if (dev->fd >= 0)
249     {
250         if (dev->stape_close_rewinds)
251         {
252             struct mtop opblk;
253 //          opblk.mt_op    = MTLOAD;    // (not sure which is more correct)
254             opblk.mt_op    = MTREW;
255             opblk.mt_count = 1;
256 
257             if ((rc = ioctl_tape ( dev->fd, MTIOCTOP, (char*)&opblk)) != 0)
258             {
259                 logmsg (_("HHCTA373W Error rewinding %u:%4.4X=%s; errno=%d: %s\n"),
260                         SSID_TO_LCSS(dev->ssid), dev->devnum,
261                         dev->filename, errno, strerror(errno));
262             }
263         }
264 
265         // Close tape drive...
266         close_tape( dev->fd );
267 
268         dev->fd        = -1;
269         dev->blockid   = -1;
270         dev->curfilen  =  0;
271         dev->nxtblkpos =  0;
272         dev->prvblkpos = -1;
273     }
274 
275     dev->sstat  = GMT_DR_OPEN(-1); // (forced)
276     dev->fenced = (rc >= 0) ? 0 : 1;
277 
278     release_lock( &sysblk.stape_lock );
279 
280 } /* end function close_scsitape */
281 
282 /*-------------------------------------------------------------------*/
283 /* Read a block from a SCSI tape device                              */
284 /*                                                                   */
285 /* If successful, return value is block length read.                 */
286 /* If a tapemark was read, the return value is zero, and the         */
287 /* current file number in the device block is incremented.           */
288 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
289 /*-------------------------------------------------------------------*/
read_scsitape(DEVBLK * dev,BYTE * buf,BYTE * unitstat,BYTE code)290 int read_scsitape (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code)
291 {
292 int  rc;
293 /* int  save_errno; */
294 
295     rc = read_tape (dev->fd, buf, MAX_BLKLEN);
296 
297     if (rc >= 0)
298     {
299         dev->blockid++;
300 
301         /* Increment current file number if tapemark was read */
302         if (rc == 0)
303             dev->curfilen++;
304 
305         /* Return block length or zero if tapemark  */
306         return rc;
307     }
308 
309     /* Handle read error condition */
310 
311     logmsg (_("HHCTA332E Error reading data block from %u:%4.4X=%s; errno=%d: %s\n"),
312             SSID_TO_LCSS(dev->ssid), dev->devnum,
313             dev->filename, errno, strerror(errno));
314 
315     if ( STS_NOT_MOUNTED( dev ) )
316         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
317     else
318         build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
319 
320     return -1;
321 
322 } /* end function read_scsitape */
323 
324 /*-------------------------------------------------------------------*/
325 /* Write a block to a SCSI tape device                               */
326 /*                                                                   */
327 /* If successful, return value is zero.                              */
328 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
329 /*-------------------------------------------------------------------*/
write_scsitape(DEVBLK * dev,BYTE * buf,U16 len,BYTE * unitstat,BYTE code)330 int write_scsitape (DEVBLK *dev, BYTE *buf, U16 len,
331                     BYTE *unitstat, BYTE code)
332 {
333 int  rc;
334 int  save_errno;
335 
336     /* Write data block to SCSI tape device */
337 
338     rc = write_tape (dev->fd, buf, len);
339 
340 #if defined( _MSVC_ )
341     if (errno == ENOSPC)
342         dev->eotwarning = 1;
343 #endif
344 
345     if (rc >= len)
346     {
347         dev->blockid++;
348         return 0;
349     }
350 
351     /*         LINUX EOM BEHAVIOUR WHEN WRITING
352 
353       When the end of medium early warning is encountered,
354       the current write is finished and the number of bytes
355       is returned. The next write returns -1 and errno is
356       set to ENOSPC. To enable writing a trailer, the next
357       write is allowed to proceed and, if successful, the
358       number of bytes is returned. After this, -1 and the
359       number of bytes are alternately returned until the
360       physical end of medium (or some other error) occurs.
361     */
362 
363     if (errno == ENOSPC)
364     {
365         int_scsi_status_update( dev, 0 );
366 
367         rc = write_tape (dev->fd, buf, len);
368 
369         if (rc >= len)
370         {
371             dev->eotwarning = 1;
372             dev->blockid++;
373             return 0;
374         }
375     }
376 
377     /* Handle write error condition... */
378 
379     save_errno = errno;
380     {
381         logmsg (_("HHCTA333E Error writing data block to %u:%4.4X=%s; errno=%d: %s\n"),
382                 SSID_TO_LCSS(dev->ssid), dev->devnum,
383                 dev->filename, errno, strerror(errno));
384 
385         int_scsi_status_update( dev, 0 );
386     }
387     errno = save_errno;
388 
389     if ( STS_NOT_MOUNTED( dev ) )
390         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
391     else
392     {
393         if (errno == EIO)
394         {
395             if(STS_EOT(dev))
396                 build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
397             else
398                 build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
399         }
400         else
401             build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code);
402     }
403 
404     return -1;
405 
406 } /* end function write_scsitape */
407 
408 /*-------------------------------------------------------------------*/
409 /* Write a tapemark to a SCSI tape device                            */
410 /*                                                                   */
411 /* If successful, return value is zero.                              */
412 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
413 /*-------------------------------------------------------------------*/
write_scsimark(DEVBLK * dev,BYTE * unitstat,BYTE code)414 int write_scsimark (DEVBLK *dev, BYTE *unitstat,BYTE code)
415 {
416 int  rc, save_errno;
417 
418     /* Write tape mark to SCSI tape */
419 
420     rc = int_write_scsimark( dev );
421 
422 #if defined( _MSVC_ )
423     if (errno == ENOSPC)
424         dev->eotwarning = 1;
425 #endif
426 
427     if (rc >= 0)
428         return 0;
429 
430     /*         LINUX EOM BEHAVIOUR WHEN WRITING
431 
432       When the end of medium early warning is encountered,
433       the current write is finished and the number of bytes
434       is returned. The next write returns -1 and errno is
435       set to ENOSPC. To enable writing a trailer, the next
436       write is allowed to proceed and, if successful, the
437       number of bytes is returned. After this, -1 and the
438       number of bytes are alternately returned until the
439       physical end of medium (or some other error) occurs.
440     */
441 
442     if (errno == ENOSPC)
443     {
444         int_scsi_status_update( dev, 0 );
445 
446         if (int_write_scsimark( dev ) >= 0)
447         {
448             dev->eotwarning = 1;
449             return 0;
450         }
451     }
452 
453     /* Handle write error condition... */
454 
455     save_errno = errno;
456     {
457         logmsg (_("HHCTA334E Error writing tapemark to %u:%4.4X=%s; errno=%d: %s\n"),
458                 SSID_TO_LCSS(dev->ssid), dev->devnum,
459                 dev->filename, errno, strerror(errno));
460 
461         int_scsi_status_update( dev, 0 );
462     }
463     errno = save_errno;
464 
465     if ( STS_NOT_MOUNTED( dev ) )
466     {
467         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
468     }
469     else
470     {
471         switch(errno)
472         {
473         case EIO:
474             if(STS_EOT(dev))
475                 build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
476             else
477                 build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
478             break;
479         case ENOSPC:
480             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
481             break;
482         default:
483             build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code);
484             break;
485         }
486     }
487 
488     return -1;
489 
490 } /* end function write_scsimark */
491 
492 /*-------------------------------------------------------------------*/
493 /* (internal 'write_scsimark' helper function)                       */
494 /*-------------------------------------------------------------------*/
int_write_scsimark(DEVBLK * dev)495 int int_write_scsimark (DEVBLK *dev)        // (internal function)
496 {
497 int  rc;
498 struct mtop opblk;
499 
500     opblk.mt_op    = MTWEOF;
501     opblk.mt_count = 1;
502 
503     rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk);
504 
505     if (rc >= 0)
506     {
507         /* Increment current file number since tapemark was written */
508         /*dev->curfilen++;*/ /* (CCW processor handles this automatically
509                              so there's no need for us to do it here) */
510 
511         /* (tapemarks count as block identifiers too!) */
512         dev->blockid++;
513     }
514 
515     return rc;
516 }
517 
518 /*-------------------------------------------------------------------*/
519 /* Synchronize a SCSI tape device   (i.e. commit its data to tape)   */
520 /*                                                                   */
521 /* If successful, return value is zero.                              */
522 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
523 /*-------------------------------------------------------------------*/
sync_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)524 int sync_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code)
525 {
526 int  rc;
527 int  save_errno;
528 struct mtop opblk;
529 
530     /*
531         GA32-0566-02 ("IBM Tape Device Drivers - Programming
532         Reference"):
533 
534         STIOCQRYPOS
535 
536         "[...] A write filemark of count 0 is always issued to
537          the drive, which flushes all data from the buffers to
538          the tape media. After the write filemark completes, the
539          query is issued."
540 
541         Write Tapemark
542 
543         "[...] The WriteTapemark entry point may also be called
544          with the dwTapemarkCount parameter set to 0 and the
545          bImmediate parameter set to FALSE. This has the effect
546          of committing any uncommitted data written by previous
547          WriteFile calls ... to the media."
548     */
549 
550     opblk.mt_op    = MTWEOF;
551     opblk.mt_count = 0;             // (zero to force a commit)
552 
553     if ((rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk)) >= 0)
554     {
555 #if defined( _MSVC_ )
556         if (errno == ENOSPC)
557             dev->eotwarning = 1;
558 #endif
559         return 0;       // (success)
560     }
561 
562     /*         LINUX EOM BEHAVIOUR WHEN WRITING
563 
564       When the end of medium early warning is encountered,
565       the current write is finished and the number of bytes
566       is returned. The next write returns -1 and errno is
567       set to ENOSPC. To enable writing a trailer, the next
568       write is allowed to proceed and, if successful, the
569       number of bytes is returned. After this, -1 and the
570       number of bytes are alternately returned until the
571       physical end of medium (or some other error) occurs.
572     */
573 
574     if (errno == ENOSPC)
575     {
576         int_scsi_status_update( dev, 0 );
577 
578         opblk.mt_op    = MTWEOF;
579         opblk.mt_count = 0;         // (zero to force a commit)
580 
581         if ((rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk)) >= 0)
582         {
583             dev->eotwarning = 1;
584             return 0;
585         }
586     }
587 
588     /* Handle write error condition... */
589 
590     save_errno = errno;
591     {
592         logmsg (_("HHCTA389E Synchronize error on "
593             "%u:%4.4X=%s; errno=%d: %s\n"),
594             SSID_TO_LCSS(dev->ssid), dev->devnum,
595             dev->filename, errno, strerror(errno));
596 
597         int_scsi_status_update( dev, 0 );
598     }
599     errno = save_errno;
600 
601     if ( STS_NOT_MOUNTED( dev ) )
602     {
603         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
604     }
605     else
606     {
607         switch(errno)
608         {
609         case EIO:
610             if(STS_EOT(dev))
611                 build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
612             else
613                 build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
614             break;
615         case ENOSPC:
616             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
617             break;
618         default:
619             build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code);
620             break;
621         }
622     }
623 
624     return -1;
625 
626 } /* end function sync_scsitape */
627 
628 /*-------------------------------------------------------------------*/
629 /* Forward space over next block of SCSI tape device                 */
630 /*                                                                   */
631 /* If successful, return value is +1.                                */
632 /* If the block skipped was a tapemark, the return value is zero,    */
633 /* and the current file number in the device block is incremented.   */
634 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
635 /*-------------------------------------------------------------------*/
fsb_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)636 int fsb_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code)
637 {
638 int  rc;
639 int  save_errno;
640 struct mtop opblk;
641 
642     /* Forward space block on SCSI tape */
643 
644     opblk.mt_op    = MTFSR;
645     opblk.mt_count = 1;
646 
647     rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk);
648 
649     if ( rc >= 0 )
650     {
651         dev->blockid++;
652         /* Return +1 to indicate forward space successful */
653         return +1;
654     }
655 
656     /* Check for spacing over a tapemark... */
657 
658     save_errno = errno;
659     {
660         int_scsi_status_update( dev, 0 );
661     }
662     errno = save_errno;
663 
664     // PROGRAMMING NOTE: please see the "Programming Note" in the
665     // 'bsb_scsitape' function regarding usage of the 'EOF' status
666     // to detect spacing over tapemarks.
667 
668     if ( EIO == errno && STS_EOF(dev) ) // (fwd-spaced over tapemark?)
669     {
670         dev->curfilen++;
671         dev->blockid++;
672         /* Return 0 to indicate tapemark was spaced over */
673         return 0;
674     }
675 
676     /* Bona fide forward space block error ... */
677 
678     save_errno = errno;
679     {
680         logmsg (_("HHCTA335E Forward space block error on %u:%4.4X=%s; errno=%d: %s\n"),
681                 SSID_TO_LCSS(dev->ssid), dev->devnum,
682                 dev->filename, errno, strerror(errno));
683     }
684     errno = save_errno;
685 
686     if ( STS_NOT_MOUNTED( dev ) )
687     {
688         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
689     }
690     else
691     {
692         switch(errno)
693         {
694         case EIO:
695             if(STS_EOT(dev))
696                 build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
697             else
698                 build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
699             break;
700         case ENOSPC:
701             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
702             break;
703         default:
704             build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code);
705             break;
706         }
707     }
708 
709     return -1;
710 
711 } /* end function fsb_scsitape */
712 
713 /*-------------------------------------------------------------------*/
714 /* Backspace to previous block of SCSI tape device                   */
715 /*                                                                   */
716 /* If successful, return value is +1.                                */
717 /* If the block is a tapemark, the return value is zero,             */
718 /* and the current file number in the device block is decremented.   */
719 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
720 /*-------------------------------------------------------------------*/
bsb_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)721 int bsb_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code)
722 {
723 int  rc;
724 int  save_errno;
725 struct mtop opblk;
726 struct mtget starting_mtget;
727 
728     /* PROGRAMMING NOTE: There is currently no way to distinguish
729     ** between a "normal" backspace-block error and a "backspaced-
730     ** into-loadpoint" i/o error, since the only error indication
731     ** we get [in response to a backspace block attempt] is simply
732     ** 'EIO'. (Interrogating the status AFTER the fact (to see if
733     ** we're positioned at loadpoint) doesn't tell us whether we
734     ** were already positioned at loadpoint *before* the error was
735     ** was encountered or whether we're only positioned at load-
736     ** point because we *did* in fact backspace over the very first
737     ** block on the tape (and are thus now, after the fact, sitting
738     ** at loadpoint because we *did* backspace over a block but it
739     ** just got an error for some reason).
740     **
741     ** Thus, we have absolutely no choice here but to retrieve the
742     ** status BEFORE we attempt the i/o to see if we're ALREADY at
743     ** loadpoint. If we are, then we immediately return an error
744     ** ("backspaced-into-loadpoint") *without* even attemting the
745     ** i/o at all. If we're *not* already sitting at loadpoint how-
746     ** ever, then we go ahead an attempt the i/o and then check for
747     ** an error afterwards.
748     */
749 
750     /* Obtain tape status before backward space... */
751     int_scsi_status_update( dev, 0 );
752 
753     /* (save the current status before the i/o in case of error) */
754     memcpy( &starting_mtget, &dev->mtget, sizeof( struct mtget ) );
755 
756     /* Unit check if already at start of tape */
757     if ( STS_BOT( dev ) )
758     {
759         dev->eotwarning = 0;
760         build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
761         return -1;
762     }
763 
764     /* Attempt the backspace i/o...*/
765     opblk.mt_op    = MTBSR;
766     opblk.mt_count = 1;
767 
768     rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk);
769 
770     if ( rc >= 0 )
771     {
772         dev->blockid--;
773         /* Return +1 to indicate backspace successful */
774         return +1;
775     }
776 
777     /* Retrieve new status after the [supposed] i/o error... */
778     save_errno = errno;
779     {
780         int_scsi_status_update( dev, 0 );
781     }
782     errno = save_errno;
783 
784     /* Check for backspacing over tapemark... */
785 
786     /* PROGRAMMING NOTE: on Windows, our scsi tape driver (w32stape.c)
787     ** sets 'EOF' status whenever a tapemark is spaced over in EITHER
788     ** direction (forward OR backward), whereas *nix operating systems
789     ** do not. They set 'EOF' status only when FORWARD spacing over a
790     ** tapemark but not when BACKSPACING over one.
791     **
792     ** (Apparently the EOF status was actually meant to mean that the
793     ** tape is "PHYSICALLY POSITIONED PAST [physical] eof" (i.e. past
794     ** an "eof marker" (i.e. a tapemark)) and nothing more. That is to
795     ** say, it is apparently NOT meant to mean a tapemark was passed
796     ** over, but rather only that you're "POSITIONED PAST" a tapemark.)
797     **
798     ** Therefore since 'EOF' status will thus *NEVER* be set whenever
799     ** a tapemark is spaced over in the *BACKWARD* direction [on non-
800     ** Windows operating systems], we need some other means of distin-
801     ** guishing between true backspace-block i/o errors and ordinary
802     ** spacing over a tapemark (which is NOT an i/o error but which
803     ** *is* an "out of the ordinary" (unit exception) type of event).
804     **
805     ** Extensive research on this issue has revealed the *ONLY* semi-
806     ** reliable means of distinguishing between them is by checking
807     ** the "file#" and "block#" fields of the status structure after
808     ** the supposed i/o error. If the file# is one less than it was
809     ** before and the block# is -1, then a tapemark was simply spaced
810     ** over. If the file# and block# is anything else however, then
811     ** the originally reported error was a bona-fide i/o error (i.e.
812     ** the original backspace-block (MTBSR) actually *failed*).
813     **
814     ** I say "semi-reliable" because comments seem to indicate that
815     ** the "file#" and "block#" fields of the mtget status structure
816     ** "are not always used". The best that I can tell however, is
817     ** most *nix operating systems *do* seem to maintain them. Thus,
818     ** for now, we're going to rely on their accuracy since without
819     ** them there's really no way whatsoever to distingish between
820     ** a normal backspacing over a tapemark unit exception condition
821     ** and a bona-fide i/o error (other than doing our own SCSI i/o
822     ** of course (which we don't support (yet))). -- Fish, May 2008
823     */
824     if ( EIO == errno )
825     {
826 #if defined( _MSVC_ )
827 
828         /* Windows always sets 'EOF' status whenever a tapemark is
829            spaced over in EITHER direction (forward OR backward) */
830 
831         if ( STS_EOF(dev) )     /* (passed over tapemark?) */
832 
833 #else // !defined( _MSVC_ )
834 
835         /* Unix-type systems unfortunately do NOT set 'EOF' whenever
836            backspacing over a tapemark (see PROGRAMMING NOTE above),
837            so we need to check the status struct's file# and block#
838            fields instead... */
839 
840         /* (passed over tapemark?) */
841         if (1
842             && dev->mtget.mt_fileno == (starting_mtget.mt_fileno - 1)
843             && dev->mtget.mt_blkno == -1
844         )
845 #endif // defined( _MSVC_ )
846         {
847             dev->curfilen--;
848             dev->blockid--;
849             /* Return 0 to indicate tapemark was spaced over */
850             return 0;
851         }
852     }
853 
854     /* Bona fide backspace block i/o error ... */
855     save_errno = errno;
856     {
857         logmsg (_("HHCTA336E Backspace block error on %u:%4.4X=%s; errno=%d: %s\n"),
858                 SSID_TO_LCSS(dev->ssid), dev->devnum,
859                 dev->filename, errno, strerror(errno));
860     }
861     errno = save_errno;
862 
863     if ( STS_NOT_MOUNTED( dev ) )
864         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
865     else
866     {
867         if ( EIO == errno && STS_BOT(dev) )
868         {
869             dev->eotwarning = 0;
870             build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
871         }
872         else
873             build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
874     }
875 
876     return -1;
877 
878 } /* end function bsb_scsitape */
879 
880 /*-------------------------------------------------------------------*/
881 /* Forward space to next file of SCSI tape device                    */
882 /*                                                                   */
883 /* If successful, the return value is zero, and the current file     */
884 /* number in the device block is incremented.                        */
885 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
886 /*-------------------------------------------------------------------*/
fsf_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)887 int fsf_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code)
888 {
889 int  rc;
890 int  save_errno;
891 struct mtop opblk;
892 
893     /* Forward space file on SCSI tape */
894 
895     opblk.mt_op    = MTFSF;
896     opblk.mt_count = 1;
897 
898     rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk);
899 
900     /* Since we have no idea how many blocks we've skipped over
901        (as a result of doing the forward-space file), we now have
902        no clue as to what the proper current blockid should be.
903     */
904     dev->blockid = -1;      // (actual position now unknown!)
905 
906     if ( rc >= 0 )
907     {
908         dev->curfilen++;
909         return 0;
910     }
911 
912     /* Handle error condition */
913 
914     dev->fenced = 1;        // (actual position now unknown!)
915 
916     save_errno = errno;
917     {
918         logmsg (_("HHCTA337E Forward space file error on %u:%4.4X=%s; errno=%d: %s\n"),
919                 SSID_TO_LCSS(dev->ssid), dev->devnum,
920                 dev->filename, errno, strerror(errno));
921     }
922     errno = save_errno;
923 
924     if ( STS_NOT_MOUNTED( dev ) )
925     {
926         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
927     }
928     else
929     {
930         switch(errno)
931         {
932         case EIO:
933             if(STS_EOT(dev))
934                 build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
935             else
936                 build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
937             break;
938         case ENOSPC:
939             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
940             break;
941         default:
942             build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code);
943             break;
944         }
945     }
946 
947     return -1;
948 
949 } /* end function fsf_scsitape */
950 
951 /*-------------------------------------------------------------------*/
952 /* Backspace to previous file of SCSI tape device                    */
953 /*                                                                   */
954 /* If successful, the return value is zero, and the current file     */
955 /* number in the device block is decremented.                        */
956 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
957 /*-------------------------------------------------------------------*/
bsf_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)958 int bsf_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code)
959 {
960 int  rc;
961 int  save_errno;
962 struct mtop opblk;
963 
964     /* PROGRAMMING NOTE: There is currently no way to distinguish
965     ** between a "normal" backspace-file error and a "backspaced-
966     ** into-loadpoint" i/o error, since the only error indication
967     ** we get [in response to a backspace file attempt] is simply
968     ** 'EIO'. (Interrogating the status AFTER the fact (to see if
969     ** we're positioned at loadpoint) doesn't tell us whether we
970     ** were already positioned at loadpoint *before* the error was
971     ** was encountered or whether we're only positioned ar load-
972     ** point because we *did* in fact backspace over a BOT tape-
973     ** mark on the tape (and are thus now, after the fact, sitting
974     ** at loadpoint because we *did* backspace over a tape-mark
975     ** but it just got an error for some reason).
976     **
977     ** Thus, we have absolutely no choice here but to retrieve the
978     ** status BEFORE we attempt the i/o to see if we're ALREADY at
979     ** loadpoint. If we are, then we immediately return an error
980     ** ("backspaced-into-loadpoint") *without* even attemting the
981     ** i/o at all. If we're *not* already sitting at loadpoint how-
982     ** ever, then we go ahead an attempt the i/o and then check for
983     ** an error afterwards.
984     */
985 
986     /* Obtain tape status before backward space... (no choice!) */
987     int_scsi_status_update( dev, 0 );
988 
989     /* Unit check if already at start of tape */
990     if ( STS_BOT( dev ) )
991     {
992         dev->eotwarning = 0;
993         build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
994         return -1;
995     }
996 
997     /* Attempt the backspace i/o...*/
998 
999     opblk.mt_op    = MTBSF;
1000     opblk.mt_count = 1;
1001 
1002     rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk);
1003 
1004     /* Since we have no idea how many blocks we've skipped over
1005        (as a result of doing the back-space file), we now have
1006        no clue as to what the proper current blockid should be.
1007     */
1008     dev->blockid = -1;      // (actual position now unknown!)
1009 
1010     if ( rc >= 0 )
1011     {
1012         dev->curfilen--;
1013         return 0;
1014     }
1015 
1016     /* Handle error condition */
1017 
1018     dev->fenced = 1;        // (actual position now unknown!)
1019 
1020     save_errno = errno;
1021     {
1022         logmsg (_("HHCTA338E Backspace file error on %u:%4.4X=%s; errno=%d: %s\n"),
1023                 SSID_TO_LCSS(dev->ssid), dev->devnum,
1024                 dev->filename, errno, strerror(errno));
1025     }
1026     errno = save_errno;
1027 
1028     if ( STS_NOT_MOUNTED( dev ) )
1029         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
1030     else
1031     {
1032         if ( EIO == errno && STS_BOT(dev) )
1033         {
1034             dev->eotwarning = 0;
1035             build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
1036         }
1037         else
1038             build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
1039     }
1040 
1041     return -1;
1042 
1043 } /* end function bsf_scsitape */
1044 
1045 /*-------------------------------------------------------------------*/
1046 /* Rewind an SCSI tape device                                        */
1047 /*-------------------------------------------------------------------*/
rewind_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)1048 int rewind_scsitape(DEVBLK *dev,BYTE *unitstat,BYTE code)
1049 {
1050 int rc;
1051 /* int  save_errno; */
1052 struct mtop opblk;
1053 
1054 //  opblk.mt_op    = MTLOAD;    // (not sure which is more correct)
1055     opblk.mt_op    = MTREW;
1056     opblk.mt_count = 1;
1057 
1058     rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk);
1059 
1060     if ( rc >= 0 )
1061     {
1062         dev->sstat |= GMT_BOT( -1 );  // (forced)
1063         dev->blockid = 0;
1064         dev->curfilen = 0;
1065         dev->fenced = 0;
1066         return 0;
1067     }
1068 
1069     dev->fenced = 1;        // (because the rewind failed)
1070     dev->blockid  = -1;     // (because the rewind failed)
1071     dev->curfilen = -1;     // (because the rewind failed)
1072 
1073     logmsg (_("HHCTA373E Error rewinding %u:%4.4X=%s; errno=%d: %s\n"),
1074             SSID_TO_LCSS(dev->ssid), dev->devnum,
1075             dev->filename, errno, strerror(errno));
1076 
1077     if ( STS_NOT_MOUNTED( dev ) )
1078         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
1079     else
1080         build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code);
1081 
1082     return -1;
1083 
1084 } /* end function rewind_scsitape */
1085 
1086 /*-------------------------------------------------------------------*/
1087 /* Rewind Unload a SCSI tape device (and CLOSE it too!)              */
1088 /*-------------------------------------------------------------------*/
int_scsi_rewind_unload(DEVBLK * dev,BYTE * unitstat,BYTE code)1089 void int_scsi_rewind_unload(DEVBLK *dev, BYTE *unitstat, BYTE code )
1090 {
1091 int rc;
1092 struct mtop opblk;
1093 
1094 //  opblk.mt_op    = MTUNLOAD;  // (not sure which is more correct)
1095     opblk.mt_op    = MTOFFL;
1096     opblk.mt_count = 1;
1097 
1098     rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk);
1099 
1100     if ( rc >= 0 )
1101     {
1102         dev->fenced = 0;
1103 
1104         if ( dev->ccwtrace || dev->ccwstep )
1105             logmsg (_("HHCTA377I Tape %u:%4.4X unloaded\n"),
1106                 SSID_TO_LCSS(dev->ssid), dev->devnum);
1107 
1108         // PR# tape/88: no sense with 'close_scsitape'
1109         // attempting a rewind if the tape is unloaded!
1110 
1111         dev->stape_close_rewinds = 0;   // (skip rewind attempt)
1112 
1113         close_scsitape( dev ); // (required for REW UNLD)
1114         return;
1115     }
1116 
1117     dev->fenced = 1;    // (because the rewind-unload failed)
1118     dev->curfilen = -1; // (because the rewind-unload failed)
1119     dev->blockid  = -1; // (because the rewind-unload failed)
1120 
1121     logmsg ( _("HHCTA376E Error unloading %u:%4.4X=%s; errno=%d: %s\n" ),
1122             SSID_TO_LCSS(dev->ssid), dev->devnum,
1123             dev->filename, errno, strerror( errno ) );
1124 
1125     if ( STS_NOT_MOUNTED( dev ) )
1126         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
1127     else
1128         build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code);
1129 
1130 } /* end function int_scsi_rewind_unload */
1131 
1132 /*-------------------------------------------------------------------*/
1133 /* Erase Gap                                                         */
1134 /*-------------------------------------------------------------------*/
erg_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)1135 int erg_scsitape( DEVBLK *dev, BYTE *unitstat, BYTE code )
1136 {
1137 #if defined( OPTION_SCSI_ERASE_GAP )
1138 int rc;
1139 
1140     if (!dev->stape_no_erg)
1141     {
1142         struct mtop opblk;
1143 
1144         opblk.mt_op    = MTERASE;
1145         opblk.mt_count = 0;         // (zero means "short" erase-gap)
1146 
1147         rc = ioctl_tape( dev->fd, MTIOCTOP, (char*)&opblk );
1148 
1149 #if defined( _MSVC_ )
1150         if (errno == ENOSPC)
1151             dev->eotwarning = 1;
1152 #endif
1153 
1154         if ( rc < 0 )
1155         {
1156             /*         LINUX EOM BEHAVIOUR WHEN WRITING
1157 
1158               When the end of medium early warning is encountered,
1159               the current write is finished and the number of bytes
1160               is returned. The next write returns -1 and errno is
1161               set to ENOSPC. To enable writing a trailer, the next
1162               write is allowed to proceed and, if successful, the
1163               number of bytes is returned. After this, -1 and the
1164               number of bytes are alternately returned until the
1165               physical end of medium (or some other error) occurs.
1166             */
1167 
1168             if (errno == ENOSPC)
1169             {
1170                 int_scsi_status_update( dev, 0 );
1171 
1172                 opblk.mt_op    = MTERASE;
1173                 opblk.mt_count = 0;         // (zero means "short" erase-gap)
1174 
1175                 if ( (rc = ioctl_tape( dev->fd, MTIOCTOP, (char*)&opblk )) >= 0 )
1176                     dev->eotwarning = 1;
1177             }
1178 
1179             if ( rc < 0)
1180             {
1181                 logmsg (_("HHCTA380E Erase Gap error on %u:%4.4X=%s; errno=%d: %s\n"),
1182                         SSID_TO_LCSS(dev->ssid), dev->devnum,
1183                         dev->filename, errno, strerror(errno));
1184                 build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
1185                 return -1;
1186             }
1187         }
1188     }
1189 
1190     return 0;       // (success)
1191 
1192 #else // !defined( OPTION_SCSI_ERASE_GAP )
1193 
1194     UNREFERENCED ( dev );
1195     UNREFERENCED ( code );
1196     UNREFERENCED ( unitstat );
1197 
1198     return 0;       // (treat as nop)
1199 
1200 #endif // defined( OPTION_SCSI_ERASE_GAP )
1201 
1202 } /* end function erg_scsitape */
1203 
1204 /*-------------------------------------------------------------------*/
1205 /* Data Security Erase                                               */
1206 /*-------------------------------------------------------------------*/
dse_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)1207 int dse_scsitape( DEVBLK *dev, BYTE *unitstat, BYTE code )
1208 {
1209 #if defined( OPTION_SCSI_ERASE_TAPE )
1210 
1211     struct mtop opblk;
1212 
1213     opblk.mt_op    = MTERASE;
1214     opblk.mt_count = 1;         // (one means "long" erase-tape)
1215 
1216     if ( ioctl_tape( dev->fd, MTIOCTOP, (char*)&opblk ) < 0 )
1217     {
1218         logmsg (_("HHCTA381E Data Security Erase error on %u:%4.4X=%s; errno=%d: %s\n"),
1219                 SSID_TO_LCSS(dev->ssid), dev->devnum,
1220                 dev->filename, errno, strerror(errno));
1221         build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
1222         return -1;
1223     }
1224 
1225     return 0;       // (success)
1226 
1227 #else // !defined( OPTION_SCSI_ERASE_TAPE )
1228 
1229     UNREFERENCED ( dev );
1230     UNREFERENCED ( code );
1231     UNREFERENCED ( unitstat );
1232 
1233     return 0;       // (treat as nop)
1234 
1235 #endif // defined( OPTION_SCSI_ERASE_TAPE )
1236 
1237 } /* end function dse_scsitape */
1238 
1239 /*-------------------------------------------------------------------*/
1240 /*                   readblkid_scsitape                              */
1241 /*-------------------------------------------------------------------*/
1242 /* Output values are returned in BIG-ENDIAN guest format...          */
1243 /*-------------------------------------------------------------------*/
readblkid_scsitape(DEVBLK * dev,BYTE * logical,BYTE * physical)1244 int readblkid_scsitape ( DEVBLK* dev, BYTE* logical, BYTE* physical )
1245 {
1246     // ZZ FIXME: The two blockid fields that READ BLOCK ID
1247     // are returning are the "Channel block ID" and "Device
1248     // block ID" fields, which correspond directly to the
1249     // SCSI "First block location" and "Last block location"
1250     // fields (as returned by a READ POSITION scsi command),
1251     // so we really SHOULD be doing our own direct scsi i/o
1252     // for ourselves so we can retrieve BOTH of those values
1253     // directly from the real/actual physical device itself,
1254     // but until we can add code to Herc to do that, we must
1255     // return the same value for each since ioctl(MTIOCPOS)
1256     // only returns us one value (the logical position) and
1257     // not both that we really prefer...
1258 
1259     // (And for the record, we want the "Channel block ID"
1260     // value, also known as the SCSI "First block location"
1261     // value, also known as the >>LOGICAL<< value and *NOT*
1262     // the absolute/physical device-relative value)
1263 
1264     struct  mtpos  mtpos;
1265     BYTE    blockid[4];
1266 
1267     if (ioctl_tape( dev->fd, MTIOCPOS, (char*) &mtpos ) < 0 )
1268     {
1269         /* Informative ERROR message if tracing */
1270 
1271         int save_errno = errno;
1272         {
1273             if ( dev->ccwtrace || dev->ccwstep )
1274                 logmsg(_("HHCTA382W ioctl_tape(MTIOCPOS=MTTELL) failed on %4.4X = %s: %s\n")
1275                     ,dev->devnum
1276                     ,dev->filename
1277                     ,strerror(errno)
1278                     );
1279         }
1280         errno = save_errno;
1281 
1282         return  -1;     // (errno should already be set)
1283     }
1284 
1285     // Convert MTIOCPOS value to guest BIG-ENDIAN format...
1286 
1287     mtpos.mt_blkno = CSWAP32( mtpos.mt_blkno );     // (guest <- host)
1288 
1289     // Handle emulated vs. physical tape-device block-id format issue...
1290 
1291     blockid_actual_to_emulated( dev, (BYTE*)&mtpos.mt_blkno, blockid );
1292 
1293     // Until we can add code to Herc to do direct SCSI i/o (so that
1294     // we can retrieve BOTH values directly from the device itself),
1295     // we have no choice but to return the same value for each since
1296     // the ioctl(MTIOCPOS) call only returns the logical value and
1297     // not also the physical value that we wish it would...
1298 
1299     if (logical)  memcpy( logical,  &blockid[0], 4 );
1300     if (physical) memcpy( physical, &blockid[0], 4 );
1301 
1302     return 0;       // (success)
1303 
1304 } /* end function readblkid_scsitape */
1305 
1306 /*-------------------------------------------------------------------*/
1307 /*                    locateblk_scsitape                             */
1308 /*-------------------------------------------------------------------*/
1309 /* Input value is passed in little-endian host format...             */
1310 /*-------------------------------------------------------------------*/
locateblk_scsitape(DEVBLK * dev,U32 blockid,BYTE * unitstat,BYTE code)1311 int locateblk_scsitape ( DEVBLK* dev, U32 blockid, BYTE *unitstat, BYTE code )
1312 {
1313     int rc;
1314     struct mtop  mtop;
1315 
1316     UNREFERENCED( unitstat );                   // (not used)
1317     UNREFERENCED(   code   );                   // (not used)
1318 
1319     // Convert the passed host-format blockid value into the proper
1320     // 32-bit vs. 22-bit guest-format the physical device expects ...
1321 
1322     blockid = CSWAP32( blockid );               // (guest <- host)
1323 
1324     blockid_emulated_to_actual( dev, (BYTE*)&blockid, (BYTE*)&mtop.mt_count );
1325 
1326     mtop.mt_count = CSWAP32( mtop.mt_count );   // (host <- guest)
1327     mtop.mt_op    = MTSEEK;
1328 
1329     // Ask the actual hardware to do an actual physical locate...
1330 
1331     if ((rc = ioctl_tape( dev->fd, MTIOCTOP, (char*)&mtop )) < 0)
1332     {
1333         int save_errno = errno;
1334         {
1335             if ( dev->ccwtrace || dev->ccwstep )
1336                 logmsg(_("HHCTA383W ioctl_tape(MTIOCTOP=MTSEEK) failed on %4.4X = %s: %s\n")
1337                     ,dev->devnum
1338                     ,dev->filename
1339                     ,strerror(errno)
1340                     );
1341         }
1342         errno = save_errno;
1343     }
1344 
1345     return rc;
1346 }
1347 
1348 /*********************************************************************/
1349 /**                                                                 **/
1350 /**                BLOCK-ID ADJUSTMENT FUNCTIONS                    **/
1351 /**                                                                 **/
1352 /*********************************************************************/
1353 /*
1354     The following conversion functions compensate for the fact that
1355     the emulated device type might actually be completely different
1356     from the actual real [SCSI] device being used for the emulation.
1357 
1358     That is to say, the actual SCSI device being used may actually
1359     be a 3590 type device but is defined in Hercules as a 3480 (or
1360     vice-versa). Thus while the device actually behaves as a 3590,
1361     we need to emulate 3480 functionality instead (and vice-versa).
1362 
1363     For 3480/3490 devices, the block ID has the following format:
1364 
1365      __________ ________________________________________________
1366     | Bit      | Description                                    |
1367     |__________|________________________________________________|
1368     | 0        | Direction Bit                                  |
1369     |          |                                                |
1370     |          | 0      Wrap 1                                  |
1371     |          | 1      Wrap 2                                  |
1372     |__________|________________________________________________|
1373     | 1-7      | Segment Number                                 |
1374     |__________|________________________________________________|
1375     | 8-9      | Format Mode                                    |
1376     |          |                                                |
1377     |          | 00     3480 format                             |
1378     |          | 01     3480-2 XF format                        |
1379     |          | 10     3480 XF format                          |
1380     |          | 11     Reserved                                |
1381     |          |                                                |
1382     |          | Note:  The 3480 format does not support IDRC.  |
1383     |__________|________________________________________________|
1384     | 10-31    | Logical Block Number                           |
1385     |__________|________________________________________________|
1386 
1387     For 3480's and 3490's, first block recorded on the tape has
1388     a block ID value of X'01000000', whereas for 3590 devices the
1389     block ID is a full 32 bits and the first block on the tape is
1390     block ID x'00000000'.
1391 
1392     For the 32-bit to 22-bit (and vice versa) conversion, we're
1393     relying on (hoping really!) that an actual 32-bit block-id value
1394     will never actually exceed 30 bits (1-bit wrap + 7-bit segment#
1395     + 22-bit block-id) since we perform the conversion by simply
1396     splitting the low-order 30 bits of a 32-bit block-id into a sep-
1397     arate 8-bit (wrap and segment#) and 22-bit (block-id) fields,
1398     and then shifting them into their appropriate position (and of
1399     course combining/appending them for the opposite conversion).
1400 
1401     As such, this of course implies that we are thus treating the
1402     wrap bit and 7-bit segment number values of a 3480/3490 "22-bit
1403     format" blockid as simply the high-order 8 bits of an actual
1404     30-bit physical blockid (which may or may not work properly on
1405     actual SCSI hardware depending on how[*] it handles inaccurate
1406     blockid values).
1407 
1408 
1409     -----------------
1410 
1411  [*]  Most(?) [SCSI] devices treat the blockid value used in a
1412     Locate CCW as simply an "approximate location" of where the
1413     block in question actually resides on the physical tape, and
1414     will, after positioning itself to the *approximate* physical
1415     location of where the block is *believed* to reside, proceed
1416     to then perform the final positioning at low-speed based on
1417     its reading of its actual internally-recorded blockid values.
1418 
1419     Thus, even when the supplied Locate block-id value is wrong,
1420     the Locate should still succeed, albeit less efficiently since
1421     it may be starting at a physical position quite distant from
1422     where the actual block is actually physically located on the
1423     actual media.
1424 */
1425 
1426 /*-------------------------------------------------------------------*/
1427 /*                  blockid_emulated_to_actual                       */
1428 /*-------------------------------------------------------------------*/
1429 /* Locate CCW helper: convert guest-supplied 3480 or 3590 blockid    */
1430 /*                    to the actual SCSI hardware blockid format     */
1431 /* Both I/P AND O/P are presumed to be in BIG-ENDIAN guest format    */
1432 /*-------------------------------------------------------------------*/
blockid_emulated_to_actual(DEVBLK * dev,BYTE * emu_blkid,BYTE * act_blkid)1433 void blockid_emulated_to_actual
1434 (
1435     DEVBLK  *dev,           // ptr to Hercules device
1436     BYTE    *emu_blkid,     // ptr to i/p 4-byte block-id in guest storage
1437     BYTE    *act_blkid      // ptr to o/p 4-byte block-id for actual SCSI i/o
1438 )
1439 {
1440     if ( TAPEDEVT_SCSITAPE != dev->tapedevt )
1441     {
1442         memcpy( act_blkid, emu_blkid, 4 );
1443         return;
1444     }
1445 
1446 #if defined(OPTION_SCSI_TAPE)
1447     if (0x3590 == dev->devtype)
1448     {
1449         // 3590 being emulated; guest block-id is full 32-bits...
1450 
1451         if (dev->stape_blkid_32)
1452         {
1453             // SCSI using full 32-bit block-ids too. Just copy as-is...
1454 
1455             memcpy( act_blkid, emu_blkid, 4 );
1456         }
1457         else
1458         {
1459             // SCSI using 22-bit block-ids. Use low-order 30 bits
1460             // of 32-bit guest-supplied blockid and convert it
1461             // into a "22-bit format" blockid value for SCSI...
1462 
1463             blockid_32_to_22 ( emu_blkid, act_blkid );
1464         }
1465     }
1466     else // non-3590 being emulated; guest block-id is 22-bits...
1467     {
1468         if (dev->stape_blkid_32)
1469         {
1470             // SCSI using full 32-bit block-ids. Extract the wrap,
1471             // segment# and 22-bit blockid bits from the "22-bit
1472             // format" guest-supplied blockid value and combine
1473             // (append) them into a contiguous low-order 30 bits
1474             // of a 32-bit blockid value for SCSI to use...
1475 
1476             blockid_22_to_32 ( emu_blkid, act_blkid );
1477         }
1478         else
1479         {
1480             // SCSI using 22-bit block-ids too. Just copy as-is...
1481 
1482             memcpy( act_blkid, emu_blkid, 4 );
1483         }
1484     }
1485 #endif /* defined(OPTION_SCSI_TAPE) */
1486 
1487 } /* end function blockid_emulated_to_actual */
1488 
1489 /*-------------------------------------------------------------------*/
1490 /*                  blockid_actual_to_emulated                       */
1491 /*-------------------------------------------------------------------*/
1492 /* Read Block Id CCW helper:  convert an actual SCSI block-id        */
1493 /*                            to guest emulated 3480/3590 format     */
1494 /* Both i/p and o/p are presumed to be in big-endian guest format    */
1495 /*-------------------------------------------------------------------*/
blockid_actual_to_emulated(DEVBLK * dev,BYTE * act_blkid,BYTE * emu_blkid)1496 void blockid_actual_to_emulated
1497 (
1498     DEVBLK  *dev,           // ptr to Hercules device (for 'devtype')
1499     BYTE    *act_blkid,     // ptr to i/p 4-byte block-id from actual SCSI i/o
1500     BYTE    *emu_blkid      // ptr to o/p 4-byte block-id in guest storage
1501 )
1502 {
1503     if ( TAPEDEVT_SCSITAPE != dev->tapedevt )
1504     {
1505         memcpy( emu_blkid, act_blkid, 4 );
1506         return;
1507     }
1508 
1509 #if defined(OPTION_SCSI_TAPE)
1510     if (dev->stape_blkid_32)
1511     {
1512         // SCSI using full 32-bit block-ids...
1513         if (0x3590 == dev->devtype)
1514         {
1515             // Emulated device is a 3590 too. Just copy as-is...
1516             memcpy( emu_blkid, act_blkid, 4 );
1517         }
1518         else
1519         {
1520             // Emulated device using 22-bit format. Convert...
1521             blockid_32_to_22 ( act_blkid, emu_blkid );
1522         }
1523     }
1524     else
1525     {
1526         // SCSI using 22-bit format block-ids...
1527         if (0x3590 == dev->devtype)
1528         {
1529             // Emulated device using full 32-bit format. Convert...
1530             blockid_22_to_32 ( act_blkid, emu_blkid );
1531         }
1532         else
1533         {
1534             // Emulated device using 22-bit format too. Just copy as-is...
1535             memcpy( emu_blkid, act_blkid, 4 );
1536         }
1537     }
1538 #endif /* defined(OPTION_SCSI_TAPE) */
1539 
1540 } /* end function blockid_actual_to_emulated */
1541 
1542 /*-------------------------------------------------------------------*/
1543 /*                     blockid_32_to_22                              */
1544 /*-------------------------------------------------------------------*/
1545 /* Convert a 3590 32-bit blockid into 3480 "22-bit format" blockid   */
1546 /* Both i/p and o/p are presumed to be in big-endian guest format    */
1547 /*-------------------------------------------------------------------*/
blockid_32_to_22(BYTE * in_32blkid,BYTE * out_22blkid)1548 void blockid_32_to_22 ( BYTE *in_32blkid, BYTE *out_22blkid )
1549 {
1550     out_22blkid[0] = ((in_32blkid[0] << 2) & 0xFC) | ((in_32blkid[1] >> 6) & 0x03);
1551     out_22blkid[1] = in_32blkid[1] & 0x3F;
1552     out_22blkid[2] = in_32blkid[2];
1553     out_22blkid[3] = in_32blkid[3];
1554 }
1555 
1556 /*-------------------------------------------------------------------*/
1557 /*                     blockid_22_to_32                              */
1558 /*-------------------------------------------------------------------*/
1559 /* Convert a 3480 "22-bit format" blockid into a 3590 32-bit blockid */
1560 /* Both i/p and o/p are presumed to be in big-endian guest format    */
1561 /*-------------------------------------------------------------------*/
blockid_22_to_32(BYTE * in_22blkid,BYTE * out_32blkid)1562 void blockid_22_to_32 ( BYTE *in_22blkid, BYTE *out_32blkid )
1563 {
1564     out_32blkid[0] = (in_22blkid[0] >> 2) & 0x3F;
1565     out_32blkid[1] = ((in_22blkid[0] << 6) & 0xC0) | (in_22blkid[1] & 0x3F);
1566     out_32blkid[2] = in_22blkid[2];
1567     out_32blkid[3] = in_22blkid[3];
1568 }
1569 
1570 /*********************************************************************/
1571 /**                                                                 **/
1572 /**           INTERNAL STATUS & AUTOMOUNT FUNCTIONS                 **/
1573 /**                                                                 **/
1574 /*********************************************************************/
1575 
1576 /* Forward references...                                             */
1577 static int   int_scsi_status_wait     ( DEVBLK* dev, int usecs );
1578 static void* get_stape_status_thread  ( void* notused );
1579 
1580 /*-------------------------------------------------------------------*/
1581 /* get_stape_status_thread                                           */
1582 /*-------------------------------------------------------------------*/
1583 static
get_stape_status_thread(void * notused)1584 void* get_stape_status_thread( void* notused )
1585 {
1586     LIST_ENTRY*   pListEntry;
1587     STSTATRQ*     req;
1588     DEVBLK*       dev = NULL;
1589     struct mtget  mtget;
1590     int           timeout;
1591 
1592     UNREFERENCED(notused);
1593 
1594     logmsg (_("HHCTA300I SCSI-Tape status monitoring thread started; "
1595             "tid="TIDPAT", pri=%d, pid=%d\n"),
1596             thread_id(), getpriority(PRIO_PROCESS,0), getpid());
1597 
1598     // PROGRAMMING NOTE: it is EXTREMELY IMPORTANT that the status-
1599     // retrieval thread (i.e. ourselves) be set to a priority that
1600     // is AT LEAST one priority slot ABOVE what the device-threads
1601     // are currently set to in order to prevent their request for
1602     // new/updated status from erroneously timing out (thereby mis-
1603     // leading them to mistakenly believe no tape is mounted when
1604     // in acuality there is!). The issue is, the caller only waits
1605     // for so long for us to return the status to them so we better
1606     // ensure we return it to them in a timely fashion else they be
1607     // mislead to believe there's no tape mounted (since, by virtue
1608     // of their request having timed out, they presume no tape is
1609     // mounted since the retrieval took too long (which only occurs
1610     // whenever (duh!) there's no tape mounted!)). Thus, if there
1611     // *is* a tape mounted, we better be DARN sure to return them
1612     // the status as quickly as possible in order to prevent their
1613     // wait from timing out. We ensure this by setting our own pri-
1614     // ority HIGHER than theirs.
1615 
1616     // PROGRAMMING NOTE: currently, it looks like each priority slot
1617     // differs from each other priority slot by '8' units, which is
1618     // why we use the value '10' here (to ensure OUR priority gets
1619     // set to the next higher slot). If this ever changes then the
1620     // below code will need to be adjusted appropriately. -- Fish
1621 
1622     SETMODE( ROOT );
1623     {
1624         setpriority( PRIO_PROCESS, 0, (sysblk.devprio - 10) );
1625     }
1626     SETMODE( USER );
1627 
1628     obtain_lock( &sysblk.stape_lock );
1629 
1630     do
1631     {
1632         sysblk.stape_getstat_busy = 1;
1633         broadcast_condition( &sysblk.stape_getstat_cond );
1634 
1635         // Process all work items currently in our queue...
1636 
1637         while (!IsListEmpty( &sysblk.stape_status_link ) && !sysblk.shutdown)
1638         {
1639             pListEntry = RemoveListHead( &sysblk.stape_status_link );
1640             InitializeListLink( pListEntry );
1641             req = CONTAINING_RECORD( pListEntry, STSTATRQ, link );
1642             dev = req->dev;
1643 
1644             // Status queries limited GLOBALLY to one per second,
1645             // since there's no way of knowing whether a drive is
1646             // on the same or different bus as the other drive(s).
1647 
1648             for
1649             (
1650                 timeout = 0
1651                 ;
1652                 1
1653                     && !sysblk.shutdown
1654                     && sysblk.stape_query_status_tod.tv_sec
1655                     && !(timeout = timed_wait_condition_relative_usecs
1656                         (
1657                             &sysblk.stape_getstat_cond,
1658                             &sysblk.stape_lock,
1659                             MAX_GSTAT_FREQ_USECS,
1660                             &sysblk.stape_query_status_tod
1661                         ))
1662                 ;
1663             );
1664 
1665             if (!sysblk.shutdown)
1666             {
1667                 // Query drive status...
1668 
1669                 // Since this may take quite a while to do if there's no tape
1670                 // mounted, we release the lock before attempting to retrieve
1671                 // the status and then re-acquire it afterwards...
1672 
1673                 release_lock( &sysblk.stape_lock );
1674                 {
1675                     define_BOT_pos( dev );  // (always before MTIOCGET)
1676 
1677                     // NOTE: the following may take up to *>10<* seconds to
1678                     // complete on Windows whenever there's no tape mounted,
1679                     // but apparently only with certain hardware. On a fast
1680                     // quad-cpu Windows 2003 Server system with an Adaptec
1681                     // AHA2944UW SCSI control for example, it completes right
1682                     // away (i.e. IMMEDIATELY), whereas on a medium dual-proc
1683                     // Windows 2000 Server system with TEKRAM SCSI controller
1684                     // it takes  *>> 10 <<*  seconds!...
1685 
1686                     if (0 == ioctl_tape( dev->fd, MTIOCGET, (char*)&mtget ))
1687                     {
1688                         memcpy( &dev->mtget, &mtget, sizeof( mtget ));
1689                     }
1690                 }
1691                 obtain_lock( &sysblk.stape_lock );
1692 
1693                 broadcast_condition( &dev->stape_sstat_cond );
1694                 gettimeofday( &sysblk.stape_query_status_tod, NULL );
1695             }
1696 
1697         } // end while (!IsListEmpty)...
1698 
1699         if (!sysblk.shutdown)
1700         {
1701             // Sleep until more/new work arrives...
1702 
1703             sysblk.stape_getstat_busy = 0;
1704             broadcast_condition( &sysblk.stape_getstat_cond );
1705             wait_condition( &sysblk.stape_getstat_cond,
1706                             &sysblk.stape_lock );
1707         }
1708     }
1709     while (!sysblk.shutdown);
1710 
1711     // (discard all work items since we're going away)
1712 
1713     while (!IsListEmpty( &sysblk.stape_status_link ))
1714     {
1715         pListEntry = RemoveListHead( &sysblk.stape_status_link );
1716         InitializeListLink( pListEntry );
1717     }
1718 
1719     logmsg (_("HHCTA301I SCSI-Tape status monitoring thread ended; "
1720             "tid="TIDPAT", pri=%d, pid=%d\n"),
1721             thread_id(), getpriority(PRIO_PROCESS,0), getpid());
1722 
1723     sysblk.stape_getstat_busy = 0;
1724     sysblk.stape_getstat_tid = 0;
1725     broadcast_condition( &sysblk.stape_getstat_cond );
1726     release_lock( &sysblk.stape_lock );
1727 
1728     return NULL;
1729 
1730 } /* end function get_stape_status_thread */
1731 
1732 /*-------------------------------------------------------------------*/
1733 /* int_scsi_status_wait                                              */
1734 /*-------------------------------------------------------------------*/
1735 static
int_scsi_status_wait(DEVBLK * dev,int usecs)1736 int int_scsi_status_wait( DEVBLK* dev, int usecs )
1737 {
1738     int rc;
1739 
1740     if (unlikely( dev->fd < 0 ))    // (has drive been opened yet?)
1741         return -1;                  // (cannot proceed until it is)
1742 
1743     obtain_lock( &sysblk.stape_lock );
1744 
1745     // Create the status retrieval thread if it hasn't been yet.
1746     // We do the actual retrieval of the status in a worker thread
1747     // because retrieving the status from a drive that doesn't have
1748     // a tape mounted may take a long time (at least on Windows).
1749 
1750     if (unlikely( !sysblk.stape_getstat_tid ))
1751     {
1752         VERIFY
1753         (
1754             create_thread
1755             (
1756                 &sysblk.stape_getstat_tid,
1757                 JOINABLE,
1758                 get_stape_status_thread,
1759                 NULL,
1760                 "get_stape_status_thread"
1761             )
1762             == 0
1763         );
1764     }
1765 
1766     // Add our request to its work queue if needed...
1767 
1768     if (!dev->stape_statrq.link.Flink)
1769     {
1770         InsertListTail( &sysblk.stape_status_link, &dev->stape_statrq.link );
1771     }
1772 
1773     // Wake up the status retrieval thread (if needed)...
1774 
1775     if (!sysblk.stape_getstat_busy)
1776     {
1777         broadcast_condition( &sysblk.stape_getstat_cond );
1778     }
1779 
1780     // Wait only so long for the status to be updated...
1781 
1782     rc = timed_wait_condition_relative_usecs
1783     (
1784         &dev->stape_sstat_cond,     // ptr to condition to wait on
1785         &sysblk.stape_lock,         // ptr to controlling lock (must be held!)
1786         usecs,                      // max #of microseconds to wait
1787         NULL                        // [OPTIONAL] ptr to tod value (may be NULL)
1788     );
1789 
1790     release_lock( &sysblk.stape_lock );
1791     return rc;
1792 } /* end function int_scsi_status_wait */
1793 
1794 /*-------------------------------------------------------------------*/
1795 /* Check if a SCSI tape is positioned past the EOT reflector or not  */
1796 /*-------------------------------------------------------------------*/
passedeot_scsitape(DEVBLK * dev)1797 int passedeot_scsitape( DEVBLK *dev )
1798 {
1799     return dev->eotwarning;     // (1==past EOT reflector; 0==not)
1800 }
1801 
1802 /*-------------------------------------------------------------------*/
1803 /* Determine if the tape is Ready   (tape drive door status)         */
1804 /* Returns:  true/false:  1 = ready,   0 = NOT ready                 */
1805 /*-------------------------------------------------------------------*/
is_tape_mounted_scsitape(DEVBLK * dev,BYTE * unitstat,BYTE code)1806 int is_tape_mounted_scsitape( DEVBLK *dev, BYTE *unitstat, BYTE code )
1807 {
1808     UNREFERENCED(unitstat);
1809     UNREFERENCED(code);
1810 
1811     /* Update tape mounted status */
1812     int_scsi_status_update( dev, 1 ); // (safe/fast internal call)
1813 
1814     return ( STS_MOUNTED( dev ) );
1815 } /* end function driveready_scsitape */
1816 
1817 /*-------------------------------------------------------------------*/
1818 /* Force a manual status refresh/update      (DANGEROUS!)            */
1819 /*-------------------------------------------------------------------*/
update_status_scsitape(DEVBLK * dev)1820 int update_status_scsitape( DEVBLK *dev )   // (external tmh call)
1821 {
1822     //                  * *  WARNING!  * *
1823 
1824     // PROGRAMMING NOTE: do NOT call this function indiscriminately,
1825     // as doing so COULD cause improper functioning of the guest o/s!
1826 
1827     // How? Simple: if there's already a tape job running on the guest
1828     // using the tape drive and we just so happen to request a status
1829     // update at the precise moment a guest i/o encounters a tapemark,
1830     // it's possible for US to receive the "tapemark" status and thus
1831     // cause the guest to end up NOT SEEING the tapemark! Therefore,
1832     // you should ONLY call this function whenever the current status
1833     // indicates there's no tape mounted. If the current status says
1834     // there *is* a tape mounted, you must NOT call this function!
1835 
1836     // If the current status says there's a tape mounted and the user
1837     // knows this to be untrue (e.g. they manually unloaded it maybe)
1838     // then to kick off the auto-scsi-mount thread they must manually
1839     // issue the 'devinit' command themselves. We CANNOT presume that
1840     // a "mounted" status is bogus. We can ONLY safely presume that a
1841     // "UNmounted" status may possibly be bogus. Thus we only ask for
1842     // a status refresh if the current status is "not mounted" but we
1843     // purposely do NOT force a refresh if the status is "mounted"!!
1844 
1845     if ( STS_NOT_MOUNTED( dev ) )           // (if no tape mounted)
1846         int_scsi_status_update( dev, 0 );   // (then probably safe)
1847 
1848     return 0;
1849 } /* end function update_status_scsitape */
1850 
1851 /*-------------------------------------------------------------------*/
1852 /* Update SCSI tape status (and display it if CCW tracing is active) */
1853 /*-------------------------------------------------------------------*/
int_scsi_status_update(DEVBLK * dev,int mountstat_only)1854 void int_scsi_status_update( DEVBLK* dev, int mountstat_only )
1855 {
1856     create_automount_thread( dev );     // (only if needed of course)
1857 
1858     // PROGRAMMING NOTE: only normal i/o requests (as well as the
1859     // scsi_tapemountmon_thread thread whenever AUTO_SCSI_MOUNT is
1860     // enabled and active) ever actually call us with mountstat_only
1861     // set to zero (in order to update our actual status value).
1862     //
1863     // Thus if we're called with a non-zero mountstat_only argument
1864     // (meaning all the caller is interested in is whether or not
1865     // there's a tape mounted on the drive (which only the panel
1866     // and GUI threads normally do (and which they do continuously
1867     // whenever they do do it!))) then we simply return immediately
1868     // so as to cause the caller to continue using whatever status
1869     // happens to already be set for the drive (which should always
1870     // be accurate).
1871     //
1872     // This prevents us from continuously "banging on the drive"
1873     // asking for the status when in reality the status we already
1874     // have should already be accurate (since it is updated after
1875     // every i/o or automatically by the auto-mount thread)
1876 
1877     if (likely(mountstat_only))           // (if only want mount status)
1878         return;                           // (then current should be ok)
1879 
1880     // Update status...
1881 
1882     if (likely(STS_MOUNTED( dev )))
1883     {
1884         // According to our current status value there is a tape mounted,
1885         // so we should wait for a full/complete/accurate status update,
1886         // regardless of however long that may take...
1887 
1888         int rc;
1889         while (ETIMEDOUT == (rc = int_scsi_status_wait( dev,
1890             MAX_GSTAT_FREQ_USECS + (2 * SLOW_UPDATE_STATUS_TIMEOUT) )))
1891         {
1892             if ( dev->ccwtrace || dev->ccwstep )
1893             {
1894                 logmsg (_("HHCTA343W %u:%4.4X Tape status retrieval timeout\n"),
1895                        SSID_TO_LCSS(dev->ssid), dev->devnum);
1896             }
1897         }
1898     }
1899     else
1900     {
1901         // No tape is mounted (or so we believe). Attempt to retrieve
1902         // an updated tape status value, but if we cannot do so within
1903         // a reasonable period of time (SLOW_UPDATE_STATUS_TIMEOUT),
1904         // then continue using whatever our current tape status is...
1905 
1906         int_scsi_status_wait( dev, SLOW_UPDATE_STATUS_TIMEOUT );
1907     }
1908 
1909     create_automount_thread( dev );     // (in case status changed)
1910 
1911     /* Display tape status if tracing is active */
1912     if (unlikely( dev->ccwtrace || dev->ccwstep ))
1913     {
1914         char  buf[256];
1915 
1916         snprintf
1917         (
1918             buf, sizeof(buf),
1919 
1920             "%u:%4.4X filename=%s (%s), sstat=0x%8.8lX: %s %s"
1921 
1922             ,SSID_TO_LCSS(dev->ssid)
1923             ,dev->devnum
1924             ,( (dev->filename[0]) ? (dev->filename) : ("(undefined)") )
1925             ,( (dev->fd   <   0 ) ?   ("closed")    : (          "opened"  ) )
1926             ,dev->sstat
1927             ,STS_ONLINE(dev)      ? "ON-LINE" : "OFF-LINE"
1928             ,STS_MOUNTED(dev)     ? "READY" : "NO-TAPE"
1929         );
1930 
1931         if ( STS_TAPEMARK(dev) ) strlcat ( buf, " TAPE-MARK"    , sizeof(buf) );
1932         if ( STS_EOF     (dev) ) strlcat ( buf, " END-OF-FILE"  , sizeof(buf) );
1933         if ( STS_BOT     (dev) ) strlcat ( buf, " LOAD-POINT"   , sizeof(buf) );
1934         if ( STS_EOT     (dev) ) strlcat ( buf, " END-OF-TAPE"  , sizeof(buf) );
1935         if ( STS_EOD     (dev) ) strlcat ( buf, " END-OF-DATA"  , sizeof(buf) );
1936         if ( STS_WR_PROT (dev) ) strlcat ( buf, " WRITE-PROTECT", sizeof(buf) );
1937 
1938         if ( STS_BOT(dev) )
1939             dev->eotwarning = 0;
1940 
1941         logmsg ( _("HHCTA323I %s\n"), buf );
1942     }
1943 
1944 } /* end function int_scsi_status_update */
1945 
1946 /*-------------------------------------------------------------------*/
1947 /*                  ASYNCHRONOUS TAPE OPEN                           */
1948 /* SCSI tape tape-mount monitoring thread (monitors for tape mounts) */
1949 /* Auto-started by 'int_scsi_status_update' when it notices there is */
1950 /* no tape mounted on whatever device it's checking the status of,   */
1951 /* or by the ReqAutoMount function for unsatisfied mount requests.   */
1952 /*-------------------------------------------------------------------*/
create_automount_thread(DEVBLK * dev)1953 void create_automount_thread( DEVBLK* dev )
1954 {
1955     //               AUTO-SCSI-MOUNT
1956     //
1957     // If no tape is currently mounted on this device,
1958     // kick off the tape mount monitoring thread that
1959     // will monitor for tape mounts (if it doesn't al-
1960     // ready still exist)...
1961 
1962     obtain_lock( &sysblk.stape_lock );
1963 
1964     // Is scsimount enabled?
1965 
1966     if (likely( sysblk.auto_scsi_mount_secs ))
1967     {
1968         // Create thread if needed...
1969 
1970         if (unlikely( !sysblk.stape_mountmon_tid ))
1971         {
1972             int rc;
1973             VERIFY
1974             (
1975                 (rc = create_thread
1976                 (
1977                     &sysblk.stape_mountmon_tid,
1978                     DETACHED,
1979                     scsi_tapemountmon_thread,
1980                     NULL,
1981                     "scsi_tapemountmon_thread"
1982                 ))
1983                 == 0
1984             );
1985         }
1986 
1987         // Enable it for our drive if needed...
1988 
1989         if (STS_NOT_MOUNTED( dev ))
1990         {
1991             if (!dev->stape_mntdrq.link.Flink)
1992             {
1993                 InsertListTail( &sysblk.stape_mount_link, &dev->stape_mntdrq.link );
1994             }
1995         }
1996     }
1997 
1998     release_lock( &sysblk.stape_lock );
1999 }
2000 
2001 /*-------------------------------------------------------------------*/
2002 /*                  ASYNCHRONOUS TAPE OPEN                           */
2003 /*-------------------------------------------------------------------*/
2004 /* AUTO_SCSI_MOUNT thread...                                         */
2005 /*-------------------------------------------------------------------*/
scsi_tapemountmon_thread(void * notused)2006 void *scsi_tapemountmon_thread( void *notused )
2007 {
2008 
2009     struct timeval  now;
2010     int             timeout, fd;
2011     LIST_ENTRY*     pListEntry;
2012     STMNTDRQ*       req;
2013     DEVBLK*         dev = NULL;
2014 
2015     UNREFERENCED(notused);
2016 
2017     logmsg
2018     (
2019         _( "HHCTA300I SCSI-Tape mount-monitoring thread started;\n"
2020            "          dev=%u:%4.4X, tid="TIDPAT", pri=%d, pid=%d\n" )
2021 
2022         ,SSID_TO_LCSS(dev->ssid)
2023         ,dev->devnum
2024         ,thread_id()
2025         ,getpriority(PRIO_PROCESS,0)
2026         ,getpid()
2027     );
2028 
2029     obtain_lock( &sysblk.stape_lock );
2030 
2031     while (sysblk.auto_scsi_mount_secs && !sysblk.shutdown)
2032     {
2033         // Wait for automount interval to expire...
2034 
2035         gettimeofday( &now, NULL );
2036 
2037         for
2038         (
2039             timeout = 0
2040             ;
2041             1
2042                 && !sysblk.shutdown
2043                 && sysblk.auto_scsi_mount_secs
2044                 && !(timeout = timed_wait_condition_relative_usecs
2045                     (
2046                         &sysblk.stape_getstat_cond,
2047                         &sysblk.stape_lock,
2048                         sysblk.auto_scsi_mount_secs * 1000000,
2049                         &now
2050                     ))
2051             ;
2052         );
2053 
2054         if (sysblk.auto_scsi_mount_secs && !sysblk.shutdown)
2055         {
2056             // Process all work items...
2057 
2058             pListEntry = sysblk.stape_mount_link.Flink;
2059 
2060             while (pListEntry != &sysblk.stape_mount_link)
2061             {
2062                 req = CONTAINING_RECORD( pListEntry, STMNTDRQ, link );
2063                 dev = req->dev;
2064                 pListEntry  = pListEntry->Flink;
2065 
2066                 // Open drive if needed...
2067 
2068                 if ((fd = dev->fd) < 0)
2069                 {
2070                     dev->readonly = 0;
2071                     fd = open_tape( dev->filename, O_RDWR | O_BINARY | O_NONBLOCK );
2072                     if (fd < 0 && EROFS == errno )
2073                     {
2074                         dev->readonly = 1;
2075                         fd = open_tape( dev->filename, O_RDONLY | O_BINARY | O_NONBLOCK );
2076                     }
2077 
2078                     // Check for successful open
2079 
2080                     if (fd < 0)
2081                     {
2082                         logmsg (_("HHCTA324E Error opening SCSI device %u:%4.4X=%s; errno=%d: %s\n"),
2083                                 SSID_TO_LCSS(dev->ssid), dev->devnum,
2084                                 dev->filename, errno, strerror(errno));
2085                         continue; // (go on to next drive)
2086                     }
2087 
2088                     define_BOT_pos( dev );  // (always after successful open)
2089                     dev->fd = fd;           // (so far so good)
2090                 }
2091 
2092                 // Retrieve the current status...
2093 
2094                 // PLEASE NOTE that we must do this WITHOUT holding the stape_lock
2095                 // since the 'int_scsi_status_update' and sub-functions all expect
2096                 // the lock to NOT be held so that THEY can then attempt to acquire
2097                 // it when needed...
2098 
2099                 release_lock( &sysblk.stape_lock );
2100                 {
2101                     int_scsi_status_update( dev, 0 );
2102                 }
2103                 obtain_lock( &sysblk.stape_lock );
2104 
2105                 // (check again for shutdown)
2106 
2107                 if (sysblk.shutdown || !sysblk.auto_scsi_mount_secs)
2108                     break;
2109 
2110                 // Has a tape [finally] been mounted yet??
2111 
2112                 if (STS_NOT_MOUNTED( dev ))
2113                 {
2114 #if !defined( _MSVC_ )
2115                     dev->fd = -1;
2116                     close_tape( fd );
2117 #endif
2118                     continue; // (go on to next drive)
2119                 }
2120 
2121                 // Yes, remove completed work item...
2122 
2123                 RemoveListEntry( &dev->stape_mntdrq.link );
2124                 InitializeListLink( &dev->stape_mntdrq.link );
2125 
2126                 // Finish the open drive process (set drive to variable length
2127                 // block processing mode, etc)...
2128 
2129                 // PLEASE NOTE that we must do this WITHOUT holding the stape_lock
2130                 // since the 'finish_scsitape_open' and sub-functions all expect
2131                 // the lock to NOT be held so that THEY can then attempt to acquire
2132                 // it when needed...
2133 
2134                 release_lock( &sysblk.stape_lock );
2135                 {
2136                     if ( finish_scsitape_open( dev, NULL, 0 ) == 0 )
2137                     {
2138                         // Notify the guest that the tape has now been loaded by
2139                         // presenting an unsolicited device attention interrupt...
2140 
2141                         device_attention( dev, CSW_DE );
2142                     }
2143                 }
2144                 obtain_lock( &sysblk.stape_lock );
2145 
2146             } // end for (all work items)...
2147 
2148         } // end if (sysblk.auto_scsi_mount_secs && !sysblk.shutdown)
2149 
2150     } // end while (sysblk.auto_scsi_mount_secs && !sysblk.shutdown)
2151 
2152     // (discard all work items since we're going away)
2153 
2154     while (!IsListEmpty( &sysblk.stape_mount_link ))
2155     {
2156         pListEntry = RemoveListHead( &sysblk.stape_mount_link );
2157         InitializeListLink( pListEntry );
2158 
2159         // (remove from the STATUS thread's work queue too!)
2160 
2161         req = CONTAINING_RECORD( pListEntry, STMNTDRQ, link );
2162         dev = req->dev;
2163 
2164         if (                     dev->stape_statrq.link.Flink) {
2165             RemoveListEntry(    &dev->stape_statrq.link );
2166             InitializeListLink( &dev->stape_statrq.link );
2167         }
2168     }
2169 
2170     logmsg
2171     (
2172         _( "HHCTA301I SCSI-Tape mount-monitoring thread ended;\n"
2173            "          dev=%u:%4.4X, tid="TIDPAT", pid=%d\n" )
2174 
2175         ,SSID_TO_LCSS(dev->ssid)
2176         ,dev->devnum
2177         ,thread_id()
2178         ,getpid()
2179     );
2180 
2181     sysblk.stape_mountmon_tid = 0;  // (we're going away)
2182     release_lock( &sysblk.stape_lock );
2183     return NULL;
2184 
2185 } /* end function scsi_tapemountmon_thread */
2186 
2187 /*-------------------------------------------------------------------*/
2188 /* Tell driver (if needed) what a BOT position looks like...         */
2189 /*-------------------------------------------------------------------*/
define_BOT_pos(DEVBLK * dev)2190 void define_BOT_pos( DEVBLK *dev )
2191 {
2192 #ifdef _MSVC_
2193 
2194     // PROGRAMMING NOTE: Need to tell 'w32stape.c' here the
2195     // information it needs to detect physical BOT (load-point).
2196 
2197     // This is not normally needed as most drivers determine
2198     // it for themselves based on the type (manufacturer/model)
2199     // of tape drive being used, but since I haven't added the
2200     // code to 'w32stape.c' to do that yet (involves talking
2201     // directly to the SCSI device itself) we thus, for now,
2202     // need to pass that information directly to 'w32stape.c'
2203     // ourselves...
2204 
2205     U32 msk  = 0xFF3FFFFF;      // (3480/3490 default)
2206     U32 bot  = 0x01000000;      // (3480/3490 default)
2207 
2208     if ( dev->stape_blkid_32 )
2209     {
2210         msk  = 0xFFFFFFFF;      // (3590 default)
2211         bot  = 0x00000000;      // (3590 default)
2212     }
2213 
2214     VERIFY( 0 == w32_define_BOT( dev->fd, msk, bot ) );
2215 
2216 #else
2217     UNREFERENCED(dev);
2218 #endif // _MSVC_
2219 }
2220 
2221 #endif // defined(OPTION_SCSI_TAPE)
2222