home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / aspio02.zip / scache.c < prev    next >
C/C++ Source or Header  |  1999-08-17  |  20KB  |  871 lines

  1. /*
  2.  * $Source: r:/source/aspi/RCS/scache.c,v $
  3.  * $Revision $
  4.  * $Date: 1999/08/18 00:20:01 $
  5.  * $Locker:  $
  6.  *
  7.  *    Change performance settings of SCSI devices.
  8.  *
  9.  * $Log: scache.c,v $
  10.  * Revision 1.6  1999/08/18 00:20:01  vitus
  11.  * - updated location of defines.h (moved)
  12.  * - changed function comments to new layout
  13.  *
  14.  * Revision 1.5  1998/11/07 21:21:00  vitus
  15.  * - added missing include<string.h>
  16.  *
  17.  * Revision 1.4  1998/03/03 03:12:22  vitus
  18.  * - added modification of CD-ROM spin down (parameter '-s')
  19.  *
  20.  * Revision 1.3  1997/09/22 02:26:17  vitus
  21.  * commented
  22.  *
  23.  * Revision 1.2  1997/09/21 03:50:52  vitus
  24.  * modifies control page and disconnect page, too
  25.  * new command line interface
  26.  *
  27.  * Revision 1.1  1997/09/19 23:37:22  vitus
  28.  * Initial revision
  29.  * ----------------------------------------
  30.  * Sample code to demonstrate use of ASPI Interface.
  31.  */
  32. static char const id[]="$Id: scache.c,v 1.6 1999/08/18 00:20:01 vitus Exp $";
  33.  
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <stdlib.h>
  37.  
  38. #define INCL_DOS
  39. #include <os2.h>
  40.  
  41. #include "../lib/defines.h"
  42. #include "scsi.h"
  43. #include "srb.h"
  44. #include "aspio.h"
  45.  
  46.  
  47.  
  48. PUBLIC char    szPrgName[_MAX_PATH];
  49.  
  50. PRIVATE struct {
  51.     int        quiet : 1;            /* 1: don't dump so many bytes */
  52. } hsFlags;
  53.  
  54.  
  55. /*
  56.  * Meanings of all SCSI releated bit fields:
  57.  * 0    don't change this feature
  58.  * 1    disable feature
  59.  * 2    enable feature
  60.  */
  61. PRIVATE struct {
  62.     int        access : 1;            /* 1: display them at least */
  63.     int        wce : 3;
  64.     int        rce : 3;
  65.     int        pre : 3;
  66.     int        prio : 3;
  67. } hsCache = {0};
  68.  
  69. PRIVATE struct {
  70.     int        access : 1;
  71.     int        queue : 3;
  72.     int        reorder : 3;
  73. } hsControl = {0};
  74.  
  75. PRIVATE struct {
  76.     int        access : 1;
  77.     int        buffer : 3;
  78.     int        inactive : 3;
  79.     int        disconnect : 3;
  80.     int        connect : 3;
  81. } hsDisconnect = {0};
  82.  
  83. PRIVATE struct {
  84.     int        access : 1;
  85.     USHORT    timeout;            /* [seconds], 0 = no change */
  86. } hsSpin = {0};
  87.  
  88. PRIVATE UCHAR    bAdp;
  89. PRIVATE UCHAR    bTarget;
  90. PRIVATE UCHAR    bLUN;
  91. PRIVATE UCHAR    abData[5000];            /* to read/write pages */
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98. PRIVATE void
  99. DumpBuffer(PVOID const arg1,ULONG const len)
  100. {
  101.     ULONG i;
  102.     PUCHAR p = arg1;
  103.  
  104.     for( i = 0; i < len; ++i, ++p )
  105.     {
  106.     printf("%02X", *p);
  107.     if( ((i + 1) % 16) == 0 )
  108.         printf("\n");
  109.     else if( ((i + 1) % 8) == 0 )
  110.         printf("-");
  111.     else
  112.         printf(" ");
  113.     }
  114.     putchar('\n');
  115. }
  116.  
  117.  
  118.  
  119.  
  120. /*# ----------------------------------------------------------------------
  121.  * Usage(void),    Help(void)
  122.  *
  123.  * PARAMETER
  124.  *    (none)
  125.  *
  126.  * RETURNS
  127.  *    (nothing)
  128.  *
  129.  * GLOBAL
  130.  *    (none)
  131.  *
  132.  * DESPRIPTION
  133.  *    Kind of online help.
  134.  *
  135.  * REMARKS
  136.  */
  137. PRIVATE void
  138. Usage(void)
  139. {
  140.     printf("%s [-?] [<settings>] <ha> <target> <lun>\n", szPrgName);
  141. }
  142.  
  143. PRIVATE void
  144. Help(void)
  145. {
  146.     Usage();
  147.     printf("\n -?\t\tthis text\n");
  148.     printf(" -v\t\tquiet\n");
  149.     printf(" +c:<string>\tenable cache page settings\n"
  150.        " -c:<string>\tdisable cache page settings\n"
  151.        "\t\tw\tenable/disable write cache\n"
  152.        "\t\tr\tenable/disable read cache\n"
  153.        "\t\tp\tenable/disable pre-fetch (read-ahead)\n"
  154.        "\t\ti\tmake pre-fetch more/less important\n");
  155.     printf(" +q:<string>\tenable control page settings\n"
  156.        " -q:<string>\tdisable control page settings\n"
  157.        "\t\tq\tenable/disable tagged queuing\n"
  158.        "\t\tr\tenable/disable reordering\n");
  159.     printf(" +d:<string>\tenable disconnect-reconnect page settings\n"
  160.        " -d:<string>\tdisable disconnect-reconnect page settings\n"
  161.        "\t\tb\tenable/disable buffer full ratio\n"
  162.        "\t\ti\tenable/disable bus inactivity limit\n"
  163.        "\t\td\tenable/disable disconnect limit\n"
  164.        "\t\tc\tenable/disable connect limit\n");
  165.     printf(" -s:<seconds>\tchange timeout until CD-ROM stops spinning\n");
  166.     printf("\nUse empty <string> to display page\n");
  167. }
  168.  
  169.  
  170.  
  171.  
  172. /*# ----------------------------------------------------------------------
  173.  * ExamineArgs(argc,argv)
  174.  *
  175.  * PARAMETER
  176.  *    argc,argv    see main()
  177.  *
  178.  * RETURNS
  179.  *    (nothing)
  180.  *
  181.  * GLOBAL
  182.  *    (nearly all)
  183.  *
  184.  * DESPRIPTION
  185.  *    Analyses command line switches and arguments and updates
  186.  *    global variables to reflect them.
  187.  *
  188.  * REMARKS
  189.  */
  190. PRIVATE void
  191. ExamineArgs(int argc,char *argv[])
  192. {
  193.     int        i;
  194.     unsigned    a = -1, t = -1, l = -1;
  195.  
  196.  
  197.     strcpy(szPrgName, argv[0]);
  198.  
  199.     while( argc > 1  &&  (argv[1][0] == '-' ||  argv[1][0] == '+') )
  200.     {
  201.     switch( argv[1][1] )
  202.     {
  203.       case '?':
  204.         Help();
  205.         exit(0);
  206.  
  207.       case 'v':
  208.         if( argv[1][0] == '-' )
  209.         hsFlags.quiet = 1;
  210.         else
  211.         hsFlags.quiet = 0;
  212.         break;
  213.  
  214.       case 'c':
  215.         hsCache.access = 1;
  216.         if( argv[1][2] == ':' )
  217.         for( i = 3; argv[1][i] != '\0'; ++i )
  218.         {
  219.             switch( argv[1][i] )
  220.             {
  221.               case 'w':
  222.             hsCache.wce = (argv[1][0] == '-' ? 1 : 2);
  223.             break;
  224.               case 'r':
  225.             hsCache.rce = (argv[1][0] == '-' ? 1 : 2);
  226.             break;
  227.               case 'p':
  228.             hsCache.pre = (argv[1][0] == '-' ? 1 : 2);
  229.             break;
  230.               case 'i':
  231.             hsCache.prio = (argv[1][0] == '-' ? 1 : 2);
  232.             break;
  233.               default:
  234.             Usage();
  235.             exit(1);
  236.             }
  237.         }
  238.         break;
  239.  
  240.       case 'q':
  241.         hsControl.access = 1;
  242.         if( argv[1][2] == ':' )
  243.         for( i = 3; argv[1][i] != '\0'; ++i )
  244.         {
  245.             switch( argv[1][i] )
  246.             {
  247.               case 'q':
  248.             hsControl.queue = (argv[1][0] == '-' ? 1 : 2);
  249.             break;
  250.               case 'r':
  251.             hsControl.reorder = (argv[1][0] == '-' ? 1 : 2);
  252.             break;
  253.               default:
  254.             Usage();
  255.             exit(1);
  256.             }
  257.         }
  258.         break;
  259.  
  260.       case 'd':
  261.         hsDisconnect.access = 1;
  262.         if( argv[1][2] == ':' )
  263.         for( i = 3; argv[1][i] != '\0'; ++i )
  264.         {
  265.             switch( argv[1][i] )
  266.             {
  267.               case 'b':
  268.             hsDisconnect.buffer = (argv[1][0] == '-' ? 1 : 2);
  269.             break;
  270.               case 'i':
  271.             hsDisconnect.inactive = (argv[1][0] == '-' ? 1 : 2);
  272.             break;
  273.               case 'd':
  274.             hsDisconnect.disconnect = (argv[1][0] == '-' ? 1 : 2);
  275.             break;
  276.               case 'c':
  277.             hsDisconnect.connect = (argv[1][0] == '-' ? 1 : 2);
  278.             break;
  279.               default:
  280.             Usage();
  281.             exit(1);
  282.             }
  283.         }
  284.         break;
  285.  
  286.       case 's':
  287.         hsSpin.access = 1;
  288.         if( argv[1][2] == ':' )
  289.         {
  290.         hsSpin.timeout = 0;
  291.         sscanf(&argv[1][3], "%hu", &hsSpin.timeout);
  292.         if( hsSpin.timeout == 0 )
  293.         {
  294.             Usage();
  295.             exit(1);
  296.         }
  297.         }
  298.         break;
  299.  
  300.       default:
  301.         Usage();
  302.         exit(1);
  303.     }
  304.     --argc;
  305.     ++argv;
  306.     }
  307.  
  308.  
  309.     if( argc == 4 )
  310.     {
  311.     sscanf(argv[1], " %u", &a);
  312.     sscanf(argv[2], " %u", &t);
  313.     sscanf(argv[3], " %u", &l);
  314.     }
  315.     if( a > 7  ||  t > 7  ||  l > 7 )
  316.     {
  317.     Usage();
  318.     exit(1);
  319.     }
  320.     bAdp = a;
  321.     bTarget = t;
  322.     bLUN = l;
  323.  
  324.     return;
  325. }
  326.  
  327.  
  328.  
  329.  
  330. /*# ----------------------------------------------------------------------
  331.  * ModifyCachePage(void)
  332.  *
  333.  * PARAMETER
  334.  *    (none)
  335.  *
  336.  * RETURNS
  337.  *    APIRET
  338.  *
  339.  * GLOBAL
  340.  *    bAdp,bTarget,bLUN
  341.  *    abData
  342.  *    hsControl
  343.  *
  344.  * DESPRIPTION
  345.  *    Try to check/modify page 8 (caching).
  346.  *    Things to be modified are coded in 'hsCache'.
  347.  *
  348.  * REMARKS
  349.  */
  350. PRIVATE APIRET
  351. ModifyCachePage(void)
  352. {
  353.     APIRET    rc;
  354.     unsigned const    pgno = 8;
  355.     UCHAR        mdlen;            /* mode data length */
  356.     PSCSI_MODEPAGE_8    page;
  357.     int            modify = 0;        /* write new value? */
  358.  
  359.  
  360.     printf("---- Mode Page %u\tcache page ----\n", pgno);
  361.  
  362.     do
  363.     {
  364.     rc = AspiModeSense(bAdp, bTarget, bLUN, pgno, 0, abData, 250);
  365.     if( rc != 0 )
  366.     {
  367.         fprintf(stderr, "\nAspiModeSense - rc %lu (%#lx)\n", rc, rc);
  368.         DumpBuffer(&strLastSense, sizeof(strLastSense));
  369.         AHSense(abData, &strLastSense),    printf(abData);
  370.         break;                /* skip this page */
  371.     }
  372.  
  373.     page = (PVOID)&abData[sizeof(SCSI_MODEPAGE_HDR)
  374.                  +sizeof(SCSI_MODEPAGE_DESCR)];
  375.  
  376.     mdlen = abData[0] + 1;        /* 'does not include itself' */
  377.     if( hsFlags.quiet == 0 )
  378.         DumpBuffer(abData, mdlen);
  379.     if( (page->pcode & 0x7F) != 0x08 )
  380.     {
  381.         printf("Unknown format!\n");
  382.         printf("Dumping complete buffer for mode page %u\n", pgno);
  383.         DumpBuffer(abData, mdlen);
  384.         break;                /* skip this page */
  385.     }
  386.  
  387.     printf("Dumping mode page %u (current values)\n", pgno);
  388.     DumpBuffer(page, sizeof(*page));
  389.  
  390.     if( hsCache.rce == 1  &&  (page->cache & 0x01) == 0 )
  391.     {
  392.         page->cache |= 0x01;        /* disable read cache */
  393.         ++modify;
  394.     }
  395.     else if( hsCache.rce == 2  &&  (page->cache & 0x01) != 0 )
  396.     {
  397.         page->cache &= ~0x01;        /* don't disable read cache */
  398.         ++modify;
  399.     }
  400.  
  401.     if( hsCache.wce == 1  &&  (page->cache & 0x04) != 0 )
  402.     {
  403.         page->cache &= ~0x04;        /* don't enable write cache */
  404.         ++modify;
  405.     }
  406.     else if( hsCache.wce == 2  &&  (page->cache & 0x04) == 0 )
  407.     {
  408.         page->cache |= 0x04;        /* enable write cache */
  409.         ++modify;
  410.     }
  411.  
  412.     if( hsCache.prio == 1  &&  page->priority != 0 )
  413.     {
  414.         page->priority = 0;            /* don't distinguish */
  415.         ++modify;
  416.     }
  417.     else if( hsCache.prio == 2  &&  page->priority != 0x11 )
  418.     {
  419.         page->priority = 0x11;        /* keep prefetched data longer */
  420.         ++modify;
  421.     }
  422.  
  423.     if( hsCache.pre == 1
  424.         &&  (page->disprefetch[0] | page->disprefetch[1]) != 0 )
  425.     {
  426.         /* Disable all pre-fetches */
  427.  
  428.         page->disprefetch[0] = 0;
  429.         page->disprefetch[1] = 0;        /* LSB */
  430.         page->minprefetch[0] = 0;
  431.         page->minprefetch[1] = 0;        /* LSB */
  432.         page->maxprefetch[0] = 0;
  433.         page->maxprefetch[1] = 0;        /* LSB */
  434.         page->prefetchceiling[0] = 0;
  435.         page->prefetchceiling[1] = 0;    /* LSB */
  436.         ++modify;
  437.     }
  438.     else if( hsCache.pre == 2
  439.          &&  (page->disprefetch[0] | page->disprefetch[1]) == 0 )
  440.     {
  441.         /* Enable pre-fetch but disable it
  442.          * on reads with more than 8KB data. */
  443.  
  444.         page->cache &= ~0x02;        /* no multipliers, real counts */
  445.         page->disprefetch[0] = 0;
  446.         page->disprefetch[1] = 32;        /* LSB */
  447.         page->minprefetch[0] = 0;
  448.         page->minprefetch[1] = 1;        /* LSB */
  449.         page->maxprefetch[0] = 0;
  450.         page->maxprefetch[1] = 16;        /* LSB */
  451.         page->prefetchceiling[0] = 0;
  452.         page->prefetchceiling[1] = 16;    /* LSB */
  453.         ++modify;
  454.     }
  455.  
  456.     if( modify )
  457.     {
  458.         page->pcode &= 0x3f;        /* mask reserved bits */
  459.         abData[0] = 0;            /* reserved in MODE SELECT */
  460.  
  461.         printf("Dumping new mode page %u and header\n", pgno);
  462.         DumpBuffer(abData, mdlen);
  463.         rc = AspiModeSelect(bAdp, bTarget, bLUN, 0, abData, mdlen);
  464.         if( rc != 0 )
  465.         {
  466.         fprintf(stderr, "\nAspiModeSelect - rc %lu (%#lx)\n", rc, rc);
  467.         DumpBuffer(&strLastSense, sizeof(strLastSense));
  468.         AHSense(abData, &strLastSense),    printf(abData);
  469.         break;                /* skip this page */
  470.         }
  471.     }
  472.     }
  473.     while( 0 );
  474.     return rc;
  475. }
  476.  
  477.  
  478.  
  479.  
  480. /*# ----------------------------------------------------------------------
  481.  * ModifyControlPage(void)
  482.  *
  483.  * PARAMETER
  484.  *    (none)
  485.  *
  486.  * RETURNS
  487.  *    APIRET
  488.  *
  489.  * GLOBAL
  490.  *    bAdp,bTarget,bLUN
  491.  *    abData
  492.  *    hsControl
  493.  *
  494.  * DESPRIPTION
  495.  *    Try to check/modify page A (control).
  496.  *    Things to be modified are coded in 'hsControl'.
  497.  *
  498.  * REMARKS
  499.  */
  500. PRIVATE APIRET
  501. ModifyControlPage(void)
  502. {
  503.     APIRET    rc;
  504.     unsigned const    pgno = 0x0A;
  505.     UCHAR        mdlen;            /* mode data length */
  506.     PSCSI_MODEPAGE_A    page;
  507.     int            modify = 0;        /* write new value? */
  508.  
  509.  
  510.     printf("---- Mode Page %u\tcontrol page ----\n", pgno);
  511.  
  512.     do
  513.     {
  514.     rc = AspiModeSense(bAdp, bTarget, bLUN, pgno, 0, abData, 250);
  515.     if( rc != 0 )
  516.     {
  517.         fprintf(stderr, "\nAspiModeSense - rc %lu (%#lx)\n", rc, rc);
  518.         DumpBuffer(&strLastSense, sizeof(strLastSense));
  519.         AHSense(abData, &strLastSense),    printf(abData);
  520.         break;                /* skip this page */
  521.     }
  522.  
  523.     page = (PVOID)&abData[sizeof(SCSI_MODEPAGE_HDR)
  524.                  +sizeof(SCSI_MODEPAGE_DESCR)];
  525.  
  526.     mdlen = abData[0] + 1;        /* 'does not include itself' */
  527.     if( hsFlags.quiet == 0 )
  528.         DumpBuffer(abData, mdlen);
  529.     if( (page->pcode & 0x7F) != 0x0A )
  530.     {
  531.         printf("Unknown format!\n");
  532.         printf("Dumping complete buffer for mode page %u\n", pgno);
  533.         DumpBuffer(abData, mdlen);
  534.         break;                /* skip this page */
  535.     }
  536.  
  537.     printf("Dumping mode page %u (current values)\n", pgno);
  538.     DumpBuffer(page, sizeof(*page));
  539.  
  540.     if( hsControl.queue == 1  &&  (page->queuing & 0x01) == 0 )
  541.     {
  542.         page->queuing |= 0x01;        /* disable tagged queuing */
  543.         ++modify;
  544.     }
  545.     else if( hsControl.queue == 2  &&  (page->queuing & 0x01) != 0 )
  546.     {
  547.         page->queuing &= ~0x01;        /* don't disable TQ */
  548.         ++modify;
  549.     }
  550.  
  551.     if( hsControl.reorder == 1  &&  (page->queuing & 0xF0) == 0x10 )
  552.     {
  553.         page->queuing &= 0x0F;        /* 'restricted reordering */
  554.         ++modify;
  555.     }
  556.     else if( hsControl.reorder == 2  &&  (page->queuing & 0xF0) != 0x10 )
  557.     {
  558.         page->queuing &= 0x0F;
  559.         page->queuing |= 0x10;        /* 'unrestricted reordering' */
  560.         ++modify;
  561.     }
  562.  
  563.     if( modify )
  564.     {
  565.         page->pcode &= 0x3f;        /* mask reserved bits */
  566.         abData[0] = 0;            /* reserved in MODE SELECT */
  567.  
  568.         printf("Dumping new mode page %u and header\n", pgno);
  569.         DumpBuffer(abData, mdlen);
  570.         rc = AspiModeSelect(bAdp, bTarget, bLUN, 0, abData, mdlen);
  571.         if( rc != 0 )
  572.         {
  573.         fprintf(stderr, "\nAspiModeSelect - rc %lu (%#lx)\n", rc, rc);
  574.         DumpBuffer(&strLastSense, sizeof(strLastSense));
  575.         AHSense(abData, &strLastSense),    printf(abData);
  576.         break;                /* skip this page */
  577.         }
  578.     }
  579.     }
  580.     while( 0 );
  581.     return rc;
  582. }
  583.  
  584.  
  585.  
  586.  
  587. /*# ----------------------------------------------------------------------
  588.  * ModifyDisconnectPage(void)
  589.  *
  590.  * PARAMETER
  591.  *    (none)
  592.  *
  593.  * RETURNS
  594.  *    APIRET
  595.  *
  596.  * GLOBAL
  597.  *    bAdp,bTarget,bLUN
  598.  *    abData
  599.  *    hsDisconnect
  600.  *
  601.  * DESPRIPTION
  602.  *    Try to check/modify page 2 (disconnect-reconnect).
  603.  *    Things to be modified are coded in 'hsDisconnect'.
  604.  *
  605.  * REMARKS
  606.  */
  607. PRIVATE APIRET
  608. ModifyDisconnectPage(void)
  609. {
  610.     APIRET    rc;
  611.     unsigned const    pgno = 0x02;
  612.     UCHAR        mdlen;            /* mode data length */
  613.     PSCSI_MODEPAGE_2    page;
  614.     int            modify = 0;        /* write new value? */
  615.  
  616.  
  617.     printf("---- Mode Page %u\tdisconnect-reconnect page ----\n", pgno);
  618.  
  619.     do
  620.     {
  621.     rc = AspiModeSense(bAdp, bTarget, bLUN, pgno, 0, abData, 250);
  622.     if( rc != 0 )
  623.     {
  624.         fprintf(stderr, "\nAspiModeSense - rc %lu (%#lx)\n", rc, rc);
  625.         DumpBuffer(&strLastSense, sizeof(strLastSense));
  626.         AHSense(abData, &strLastSense),    printf(abData);
  627.         break;                /* skip this page */
  628.     }
  629.  
  630.     page = (PVOID)&abData[sizeof(SCSI_MODEPAGE_HDR)
  631.                  +sizeof(SCSI_MODEPAGE_DESCR)];
  632.  
  633.     mdlen = abData[0] + 1;        /* 'does not include itself' */
  634.     if( hsFlags.quiet == 0 )
  635.         DumpBuffer(abData, mdlen);
  636.     if( (page->pcode & 0x7F) != 0x02 )
  637.     {
  638.         printf("Unknown format!\n");
  639.         printf("Dumping complete buffer for mode page %u\n", pgno);
  640.         DumpBuffer(abData, mdlen);
  641.         break;                /* skip this page */
  642.     }
  643.  
  644.     printf("Dumping mode page %u (current values)\n", pgno);
  645.     DumpBuffer(page, sizeof(*page));
  646.  
  647.     if( hsDisconnect.buffer == 1
  648.         &&  (page->bfull |  page->bempty) != 0 )
  649.     {
  650.         /* no disconnect because of full/empty buffers */
  651.  
  652.         page->bfull = 0;
  653.         page->bempty = 0;
  654.         ++modify;
  655.     }
  656.     else if( hsDisconnect.buffer == 2
  657.          &&  (page->bfull |  page->bempty) == 0 )
  658.     {
  659.         /* disconnect because of full/empty buffers */
  660.  
  661.         page->bfull = 40;            /* ~15% */
  662.         page->bempty = 40;
  663.         ++modify;
  664.     }
  665.  
  666.     if( hsDisconnect.inactive == 1
  667.          &&  (page->businactive[0] |  page->businactive[1]) != 0 )
  668.     {
  669.         /* no limit on bus busy time w/o connection */
  670.  
  671.         page->businactive[0] = page->businactive[1] = 0;
  672.         ++modify;
  673.     }
  674.     else if( hsDisconnect.inactive == 2
  675.          &&  (page->businactive[0] |  page->businactive[1]) == 0 )
  676.     {
  677.         /* don't keep bus busy w/o connection */
  678.  
  679.         page->businactive[0] = 0;
  680.         page->businactive[1] = 200;        /* LSB */
  681.         ++modify;
  682.     }
  683.  
  684.     if( modify )
  685.     {
  686.         page->pcode &= 0x3f;        /* mask reserved bits */
  687.         abData[0] = 0;            /* reserved in MODE SELECT */
  688.  
  689.         printf("Dumping new mode page %u and header\n", pgno);
  690.         DumpBuffer(abData, mdlen);
  691.         rc = AspiModeSelect(bAdp, bTarget, bLUN, 0, abData, mdlen);
  692.         if( rc != 0 )
  693.         {
  694.         fprintf(stderr, "\nAspiModeSelect - rc %lu (%#lx)\n", rc, rc);
  695.         DumpBuffer(&strLastSense, sizeof(strLastSense));
  696.         AHSense(abData, &strLastSense),    printf(abData);
  697.         break;                /* skip this page */
  698.         }
  699.     }
  700.     }
  701.     while( 0 );
  702.     return rc;
  703. }
  704.  
  705.  
  706.  
  707.  
  708. /*# ----------------------------------------------------------------------
  709.  * ModifySpinning(void)
  710.  *
  711.  * PARAMETER
  712.  *    (none)
  713.  *
  714.  * RETURNS
  715.  *    APIRET
  716.  *
  717.  * GLOBAL
  718.  *    bAdp,bTarget,bLUN
  719.  *    abData
  720.  *    hwSpin
  721.  *
  722.  * DESPRIPTION
  723.  *    Try to modify page 0D (time in hold track state)
  724.  *    Things to be modified are coded in 'hsSpin'.
  725.  *
  726.  * REMARKS
  727.  */
  728. PRIVATE APIRET
  729. ModifySpinning(void)
  730. {
  731.     APIRET    rc;
  732.     unsigned const    pgno = 0x0D;
  733.     UCHAR        mdlen;            /* mode data length */
  734.     PSCSI_MODEPAGE_D    page;
  735.     int            modify = 0;        /* write new value? */
  736.  
  737.  
  738.     printf("---- Mode Page %u\tCD-ROM parameters page ----\n", pgno);
  739.  
  740.     do
  741.     {
  742.     rc = AspiModeSense(bAdp, bTarget, bLUN, pgno, 0, abData, 250);
  743.     if( rc != 0 )
  744.     {
  745.         fprintf(stderr, "\nAspiModeSense - rc %lu (%#lx)\n", rc, rc);
  746.         DumpBuffer(&strLastSense, sizeof(strLastSense));
  747.         AHSense(abData, &strLastSense),    printf(abData);
  748.         break;                /* skip this page */
  749.     }
  750.  
  751.     page = (PVOID)&abData[sizeof(SCSI_MODEPAGE_HDR)
  752.                  +sizeof(SCSI_MODEPAGE_DESCR)];
  753.  
  754.     mdlen = abData[0] + 1;        /* 'does not include itself' */
  755.     if( hsFlags.quiet == 0 )
  756.         DumpBuffer(abData, mdlen);
  757.     if( (page->pcode & 0x7F) != 0x0D )
  758.     {
  759.         printf("Unknown format!\n");
  760.         printf("Dumping complete buffer for mode page %u\n", pgno);
  761.         DumpBuffer(abData, mdlen);
  762.         break;                /* skip this page */
  763.     }
  764.  
  765.     printf("Dumping mode page %u (current values)\n", pgno);
  766.     DumpBuffer(page, sizeof(*page));
  767.  
  768.     if( hsSpin.timeout != 0 )
  769.     {
  770.         if( hsSpin.timeout == 1 )
  771.         page->multiplier = 0x04;
  772.         else if( hsSpin.timeout == 2 )
  773.         page->multiplier = 0x05;
  774.         else if( hsSpin.timeout <= 4 )
  775.         page->multiplier = 0x06;
  776.         else if( hsSpin.timeout <= 8 )
  777.         page->multiplier = 0x07;
  778.         else if( hsSpin.timeout <= 16 )
  779.         page->multiplier = 0x08;
  780.         else if( hsSpin.timeout <= 32 )
  781.         page->multiplier = 0x09;
  782.         else if( hsSpin.timeout <= 60 )
  783.         page->multiplier = 0x0A;
  784.         else if( hsSpin.timeout <= 120 )
  785.         page->multiplier = 0x0B;
  786.         else if( hsSpin.timeout <= 240 )
  787.         page->multiplier = 0x0C;
  788.         else if( hsSpin.timeout <= 480 )
  789.         page->multiplier = 0x0D;
  790.         else if( hsSpin.timeout <= 960 )
  791.         page->multiplier = 0x0E;
  792.         else if( hsSpin.timeout <= 1920 )
  793.         page->multiplier = 0x0F;
  794.         ++modify;
  795.     }
  796.  
  797.     if( modify )
  798.     {
  799.         page->pcode &= 0x3f;        /* mask reserved bits */
  800.         abData[0] = 0;            /* reserved in MODE SELECT */
  801.  
  802.         printf("Dumping new mode page %u and header\n", pgno);
  803.         DumpBuffer(abData, mdlen);
  804.         rc = AspiModeSelect(bAdp, bTarget, bLUN, 0, abData, mdlen);
  805.         if( rc != 0 )
  806.         {
  807.         fprintf(stderr, "\nAspiModeSelect - rc %lu (%#lx)\n", rc, rc);
  808.         DumpBuffer(&strLastSense, sizeof(strLastSense));
  809.         AHSense(abData, &strLastSense),    printf(abData);
  810.         break;                /* skip this page */
  811.         }
  812.     }
  813.     }
  814.     while( 0 );
  815.     return rc;
  816. }
  817.  
  818.  
  819.  
  820.  
  821.  
  822.  
  823. PUBLIC int
  824. main(int argc,char *argv[])
  825. {
  826.     APIRET    rc;
  827.     UCHAR    type;                /* see SCSI spec */
  828.  
  829.     ExamineArgs(argc, argv);
  830.  
  831.     rc = AspiOpen(0);
  832.     if( rc != 0 )
  833.     {
  834.     fprintf(stderr, "\nAspiOpen - rc %lu\n", rc);
  835.     return rc;
  836.     }
  837.  
  838.     do
  839.     {
  840.     rc = AspiGetType(bAdp, bTarget, bLUN, &type);
  841.     if( rc != 0 )
  842.     {
  843.         fprintf(stderr, "\nAspiGetType - rc %lu (%#lx)\n", rc, rc);
  844.         break;
  845.     }
  846.  
  847.     printf("HA %u  Target %u  LUN %u\t\"%s\" (%s)\n",
  848.            bAdp, bTarget, bLUN,
  849.            AHInquiryType(type), AHInquiryQual(type));
  850.  
  851.     if( hsCache.access )
  852.         rc = ModifyCachePage();
  853.     if( hsControl.access )
  854.         rc = ModifyControlPage();
  855.     if( hsDisconnect.access )
  856.         rc = ModifyDisconnectPage();
  857.     if( hsSpin.access )
  858.         rc = ModifySpinning();
  859.     }
  860.     while( 0 );
  861.  
  862.     rc = AspiClose();
  863.     if( rc != 0 )
  864.     {
  865.     fprintf(stderr, "\nAspiClose - rc %lu (%#lx)\n", rc, rc);
  866.     return rc;
  867.     }
  868.  
  869.     return 0;
  870. }
  871.