home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / share / YaST2 / modules / Idedma.ycp < prev    next >
Text File  |  2006-11-29  |  17KB  |  657 lines

  1. /**
  2.  * File:
  3.  *   modules/Idedma.ycp
  4.  *
  5.  * Package:
  6.  *   Configuration of IDE DMA mode
  7.  *
  8.  * Summary:
  9.  *   Data for configuration of IDE DMA mode, input and output functions.
  10.  *
  11.  * Authors:
  12.  *   Ladislav Slezak <lslezak@suse.cz>
  13.  *
  14.  * $Id: Idedma.ycp 30771 2006-05-09 14:43:39Z lslezak $
  15.  *
  16.  * Representation of the configuration of IDE DMA mode.
  17.  * Input and output routines.
  18.  *
  19.  */
  20.  
  21. {
  22.     // Set the name of the module
  23.     module "Idedma";
  24.     import "Report";
  25.     import "Service";
  26.  
  27.     include "hwinfo/classnames.ycp";
  28.  
  29.     textdomain "tune";
  30.  
  31.     // Settings: Define all variables needed for configuration of IDE DMA
  32.  
  33.     /**
  34.      * List of all IDE devices with descriptions and DMA settings
  35.      */
  36.     list<map<string,any> > ide_devices = [];
  37.  
  38.     /**
  39.      * Full path to hdparm binary
  40.      */
  41.     string hdparm_bin = "/sbin/hdparm";
  42.  
  43.     /**
  44.      * Full path to udev script which sets the DMA mode
  45.      */
  46.     string udev_script = "/lib/udev/idedma.sh";
  47.  
  48.     /**
  49.      * String with DMA on status text
  50.      * (For translators: translation can be long - text is used in the table
  51.      * in column "Required DMA mode" and "Current DMA mode")
  52.      */
  53.     global string dma_on_string = _("On");
  54.  
  55.     /**
  56.      * String with DMA off status text
  57.      * (For translators: translation can be long - text is used in the table
  58.      * in column "Required DMA mode" and "Current DMA mode")
  59.      */
  60.     global string dma_off_string = _("Off");
  61.  
  62.     /**
  63.      * String with no change of DMA status text
  64.      * (For translators: translation can be long - text is used in the table
  65.      * in column "Required DMA mode" and "Current DMA mode")
  66.      */
  67.     global string dma_default_string = _("No change");
  68.  
  69.  
  70.     global map mode_names = $[
  71.     // DMA status is unknown
  72.     ""      : _("Unknown"),
  73.     // do not change DMA setting
  74.     "nochange"    : dma_default_string,
  75.     // DMA is enabled, but mode is unknown
  76.     "on"    : dma_on_string,
  77.     // DMA is disabled
  78.     "off"   : dma_off_string,
  79.  
  80.     "sdma0" : "SW DMA/2.1",
  81.     "sdma1" : "SW DMA/4.2",
  82.     "sdma2" : "SW DMA/8.3",
  83.  
  84.     "mdma0" : "DMA/4.2",
  85.     "mdma1" : "DMA/13.3",
  86.     "mdma2" : "DMA/16",
  87.  
  88.     "udmaS" : "UltraDMA/13",
  89.     "udma0" : "UltraDMA/16",
  90.     "udma1" : "UltraDMA/22",
  91.     "udma2" : "UltraDMA/33",
  92.     "udma3" : "UltraDMA/44",
  93.     "udma4" : "UltraDMA/66",
  94.     "udma5" : "UltraDMA/100",
  95.     "udma6" : "UltraDMA/133"
  96.     ];
  97.  
  98.     /**
  99.      * Return actual DMA status of IDE device
  100.      * @param device Identification of ide device, e.g. "/dev/hdc"
  101.      * @return string true if DMA is on, false if DMA is off or nil on error
  102.      */
  103.     global define string get_device_dma_status(string device) ``{
  104.     string result = "";
  105.  
  106.     if (device != nil && device != "")
  107.     {
  108.         // run hdparm to get DMA status
  109.         map out = (map) SCR::Execute(.target.bash_output, hdparm_bin + " -d " + device);
  110.  
  111.         if (out["exit"]:-1 == 0)
  112.         {
  113.         list<string> output = splitstring(out["stdout"]:"", "\n");
  114.  
  115.         y2debug("hdparm output: %1", output);
  116.  
  117.         // search for status string in output
  118.         foreach(string l, output, ``{
  119.  
  120.             if (l == " using_dma    =  1 (on)")
  121.             {
  122.                 result = "on";
  123.  
  124.             }
  125.  
  126.             if (l == " using_dma    =  0 (off)")
  127.             {
  128.                 result = "off";
  129.             }
  130.             }
  131.         );
  132.         }
  133.     }
  134.  
  135.     return result;
  136.     }
  137.  
  138.     /**
  139.      * Get DMA information status for device
  140.      * @param device device name (e.g. "/dev/hdc")
  141.      * @return string DMA information from hdparm ("mdma2 udma0 udma1 *udma2")
  142.      */
  143.     define string get_dma_info(string device) ``{
  144.     string result = "";
  145.  
  146.     if (device != nil && device != "")
  147.     {
  148.         // DMA mode is enabled, get DMA mode number
  149.         map out = (map) SCR::Execute(.target.bash_output, hdparm_bin + " -I " + device);
  150.  
  151.         if (out["exit"]:-1 == 0)
  152.         {
  153.         list<string> output = splitstring(out["stdout"]:"", "\n");
  154.  
  155.         foreach(string line, output, ``{
  156.             string dmaline = (regexpsub(line, "^[ \t]*DMA:[ \t]*(.*)$", "\\1"));
  157.  
  158.             if (dmaline != nil)
  159.             {
  160.                 y2debug("dmaline: %1", dmaline);
  161.                 result = (result == "") ? dmaline : (result + " " + dmaline);
  162.             }
  163.             }
  164.         );
  165.         }
  166.     }
  167.  
  168.     y2debug("device: %1 DMA modes: %2", device, result);
  169.  
  170.     return result;
  171.     }
  172.  
  173.  
  174.     /**
  175.      * Parse DMA info string from hdparm output - return current DMA mode (has mark '*')
  176.      * @param dma_info DMA support string (e.g. "mdma2 udma0 udma1 *udma2")
  177.      * @return string current DMA mode or "" if unknown
  178.      */
  179.     define string get_current_dma_mode(string dma_info) ``{
  180.     string result = "";
  181.  
  182.     if (dma_info != nil && dma_info != "")
  183.     {
  184.         list<string> modes = splitstring(dma_info, " ");
  185.  
  186.         foreach(string mode, modes, ``{
  187.             string current = regexpsub(mode, "^\\*(.*)", "\\1");
  188.  
  189.             if (current != nil)
  190.             {
  191.             result = current;
  192.             }
  193.         }
  194.         );
  195.     }
  196.  
  197.     return result;
  198.     }
  199.  
  200.     /**
  201.      * Parse DMA info string from hdparm output - return list of supported DMA modes
  202.      * @param dma_info DMA support string (e.g. "mdma2 udma0 udma1 *udma2")
  203.      * @return list<string> list of supported DMA modes
  204.      */
  205.     define list<string> get_supported_dma_modes(string dma_info) ``{
  206.     list<string> result = [];
  207.  
  208.     if (dma_info != nil && dma_info != "")
  209.     {
  210.         list<string> modes = splitstring(dma_info, " ");
  211.  
  212.         foreach(string mode, modes, ``{
  213.  
  214.             if (size(mode) > 0)
  215.             {
  216.             string current = regexpsub(mode, "^\\*(.*)", "\\1");
  217.  
  218.             // add mode or current mode (filter out * mark)
  219.             result = add(result, (current != nil) ? current : mode);
  220.             }
  221.         }
  222.         );
  223.     }
  224.     else
  225.     {
  226.         // DMA info line is empty - no information is available
  227.         // offer all possible values
  228.         result = [ "mdma2", "udma0", "udma2", "udma4", "udma5", "udma6"];
  229.     }
  230.  
  231.     return result;
  232.     }
  233.  
  234.     /**
  235.      * Read all DMA settings from the SCR
  236.      * @return boolean true on success
  237.      */
  238.     global define boolean Read() ``{
  239.     ide_devices = [];
  240.  
  241.     // read information about all IDE devices
  242.     list<map<string,any> > devices = (list<map<string, any> >) SCR::Read(.probe.ide);
  243.  
  244.     // remove SATA devices (/dev/sd*)
  245.     devices = filter(map<string,any> dn, devices, {
  246.         string d = dn["dev_name"]:"";
  247.         return regexpmatch(d, "^/dev/hd");
  248.         }
  249.     );
  250.  
  251.     // read SCSI devices
  252.     list<map<string,any> > scsi_devices = (list<map<string, any> >) SCR::Read(.probe.scsi);
  253.  
  254.     if (size(scsi_devices) > 0)
  255.     {
  256.         // leave only devices with IDE-SCSI emulation
  257.         scsi_devices = filter(map<string,any> dev, scsi_devices, ``(dev["driver"]:nil == "ide-scsi"));
  258.     }
  259.  
  260.     // add ide-scsi devices to ide devices
  261.     if (size(scsi_devices) > 0)
  262.     {
  263.         devices = (list<map<string,any> >) merge(devices, scsi_devices);
  264.     }
  265.  
  266.     y2milestone("Detected ide-scsi devices: %1", scsi_devices);
  267.  
  268.     // read setting from sysconfig
  269.     string devices_setting_str = (string) SCR::Read(.sysconfig.ide.DEVICES_FORCE_IDE_DMA);
  270.  
  271.     y2debug("Read configuration: %1", devices_setting_str);
  272.  
  273.     if (devices_setting_str == nil)
  274.     {
  275.         devices_setting_str = "";
  276.     }
  277.  
  278.  
  279.     // split string to list of devices
  280.     list<string> device_settings = splitstring(devices_setting_str, " ");
  281.  
  282.     // create map of settings <device>:<DMA_setting>
  283.     map device_setting_map = $[];
  284.  
  285.     foreach(string setting, device_settings, ``{
  286.         string dev =  regexpsub(setting, "^(.*):(.*)", "\\1");
  287.         string mode =  regexpsub(setting, "^(.*):(.*)", "\\2");
  288.  
  289.         if (size(dev) > 0 && size(mode) > 0)
  290.         {
  291.             device_setting_map = add(device_setting_map, dev, mode);
  292.         }
  293.         }
  294.     );
  295.  
  296.  
  297.     y2milestone("Read config: %1", device_setting_map);
  298.  
  299.     // for each detected IDE device build internal
  300.     foreach(map<string, any> dev, devices, ``{
  301.         // device model name is unknown
  302.         string device = (string) (dev["device"]:_("Unknown device"));
  303.         string dev_name = (string) (dev["dev_name"]:nil);
  304.         string scsi_name = nil;
  305.  
  306.         if (dev["driver"]:nil == "ide-scsi")
  307.         {
  308.             // this is ide-scsi device
  309.             // set device name to IDE name
  310.             dev_name = (string) (dev["dev_name2"]:nil);
  311.             scsi_name = (string) (dev["dev_name"]:nil);
  312.         }
  313.  
  314.         if (dev_name != nil)
  315.         {
  316.             integer subclass_id = (integer) (dev["sub_class_id"]:nil);
  317.             integer class_id = (integer) (dev["class_id"]:nil);
  318.  
  319.             string dma_setting = device_setting_map[dev_name]:"nochange";
  320.  
  321.             // get textual information about device type (disk, CD-ROM, tape, ...) from identification number - device type was not found
  322.             string subclass_id_string = (string) eval(ClassNames[class_id, subclass_id]: _("Unknown device type"));
  323.  
  324.             // get current DMA setting
  325.             string current_dma = get_device_dma_status(dev_name);
  326.             string dma_info = get_dma_info(dev_name);
  327.  
  328.             y2milestone("dma_info: %1", dma_info);
  329.  
  330.             string current_dma_string = get_current_dma_mode(dma_info);
  331.             if (current_dma == "on" && size(current_dma_string) > 0)
  332.             {
  333.             current_dma = current_dma_string;
  334.             }
  335.  
  336.             list<string> dma_modes = get_supported_dma_modes(dma_info);
  337.  
  338.             map<string,any> dev_map = $["device" : device, "dev_name" : dev_name, "dma_setting" : dma_setting, "device_type" : subclass_id_string, "current_dma" : current_dma, "dma_modes" : dma_modes];
  339.  
  340.             if (scsi_name != nil)
  341.             {
  342.             // add scsi name if device is ide-scsi
  343.             dev_map["scsi_name"] = scsi_name;
  344.             }
  345.  
  346.             ide_devices = (list<map<string,any> >) add(ide_devices, dev_map);
  347.         }
  348.         }
  349.     );
  350.  
  351.     y2milestone("Detected IDE devices: %1", ide_devices);
  352.  
  353.     return true;
  354.     }
  355.  
  356.  
  357.     /**
  358.      * Return information about all IDE devices
  359.      * @return list List of maps with information about all IDE devices
  360.      */
  361.     global define list<map> get_ide_devices() ``{
  362.     return ide_devices;
  363.     }
  364.  
  365.     /**
  366.      * Get list of supported DMA modes for selected device
  367.      * @param device device name ("/dev/hda")
  368.      * @return list supported DMA modes (["mdma2", "udma0", "udma1", "udma2"])
  369.      */
  370.     global define list supported_dma_modes(string device) ``{
  371.     list result = [];
  372.  
  373.     if (size(device) > 0)
  374.     {
  375.         foreach(map info, ide_devices, ``{
  376.             if (info["dev_name"]:"" == device)
  377.             {
  378.             result = info["dma_modes"]:[];
  379.             }
  380.         }
  381.         );
  382.     }
  383.  
  384.     return result;
  385.     }
  386.  
  387.     /**
  388.      * Get selected DMA mode, which will be saved and set in Write
  389.      * @param device device name ("/dev/hda")
  390.      * @return string selected DMA mode ("on", "off", "nochange", or mode supported by hdparm - "udma5",...)
  391.      */
  392.     global define string selected_mode(string device) ``{
  393.     string mode = "";
  394.  
  395.     if (size(device) > 0)
  396.     {
  397.         foreach(map info, ide_devices, ``{
  398.             if (info["dev_name"]:"" == device)
  399.             {
  400.             mode = info["dma_setting"]:"";
  401.             }
  402.         }
  403.         );
  404.     }
  405.  
  406.     return mode;
  407.     }
  408.  
  409.     /**
  410.      * Set DMA of device
  411.      * @param device Identification of IDE device, e.g. "/dev/hda"
  412.      * @param dma_setting DMA mode (e.g. "mdma2", "udma5", "off",...)
  413.      * @return boolean true on success
  414.      */
  415.     global define boolean set_dma(string device, string dma_setting) ``{
  416.     if (device == nil || device == "" || dma_setting == nil || dma_setting == "")
  417.     {
  418.         return false;
  419.     }
  420.  
  421.     // check if mode name in known
  422.     if (!haskey(mode_names, dma_setting))
  423.     {
  424.         return false;
  425.     }
  426.  
  427.     // store required DMA status
  428.     ide_devices = maplist(map<string,any> d, ide_devices, ``{
  429.         if (d["dev_name"]:nil == device)
  430.         {
  431.             d = add(d, "dma_setting", dma_setting);
  432.         }
  433.  
  434.         return d;
  435.         }
  436.     );
  437.  
  438.     return true;
  439.     }
  440.  
  441.     /**
  442.      * Update the SCR according to DMA settings
  443.      * @return boolean true on success
  444.      */
  445.     global define boolean Write() ``{
  446.     boolean ret = true;
  447.  
  448.     // create strings with device indentifications
  449.     // e.g. new_dma_setting = "/dev/hda:udma5 /dev/hdc:off";
  450.     string new_dma_setting = "";
  451.     boolean first = true;
  452.  
  453.     // is boot.idedma init script needed?
  454.     // avoid calling hdparm if configuration wasn't changed
  455.     boolean initscript_needed = false;
  456.     // is sync call needed?
  457.     // call sync before DMA is turned on, usefull when machine
  458.     // hangs just after enabling DMA
  459.     boolean sync_needed = false;
  460.  
  461.     map<string,string> changeDMA = $[];
  462.  
  463.     y2milestone("ide_devices: %1", ide_devices);
  464.  
  465.     foreach(map<string, any> d, ide_devices, ``{
  466.         string d_name = (string) (d["dev_name"]:nil);
  467.  
  468.         if (d_name != nil)
  469.         {
  470.             string dma_setting = (string) (d["dma_setting"]:"nochange");
  471.  
  472.             string dma_current_setting = (string) (d["current_dma"]:"nochange");
  473.             string dma_required_setting = dma_setting;
  474.  
  475.             if (dma_setting != "nochange")
  476.             {
  477.             y2debug("d_name: %1  dma_setting: %2", d_name, dma_setting);
  478.             dma_setting = d_name + ":" + dma_setting;
  479.  
  480.             if (first == true)
  481.             {
  482.                 new_dma_setting = dma_setting;
  483.                 first = false;
  484.             }
  485.             else
  486.             {
  487.                 new_dma_setting = new_dma_setting + " " + dma_setting;
  488.             }
  489.  
  490.             y2debug("dma_setting: %1, dma_current_setting: %2", dma_setting, dma_current_setting);
  491.  
  492.             // use boot.idedma only if current DMA mode and required DMA mode differ
  493.             if (dma_required_setting != dma_current_setting &&
  494.                 // don't distinguish between "on" and exact DMA mode
  495.                 // (required is "on", current is not "off" nor "nochange" (it is e.g. "udma2"))
  496.                 !(dma_required_setting == "on" && dma_current_setting != "off" && dma_current_setting != "nochange")
  497.             )
  498.             {
  499.                 initscript_needed = true;
  500.  
  501.                 if (dma_current_setting == "off" && dma_required_setting != "off" && dma_required_setting != "nochange")
  502.                 {
  503.                 sync_needed = true;
  504.                 }
  505.  
  506.                 // remember the new setting
  507.                 changeDMA[d_name] = dma_required_setting;
  508.             }
  509.             }
  510.         }
  511.         }
  512.     );
  513.  
  514.     y2milestone("new_dma_setting: %1", new_dma_setting);
  515.  
  516.     // write device strings to sysconfig
  517.     if (SCR::Write(.sysconfig.ide.DEVICES_FORCE_IDE_DMA, new_dma_setting) == false)
  518.     {
  519.         // error message - %1 is file name
  520.         Report::Error(sformat(_("Unable to write settings to '%1'."), "/etc/sysconfig/ide"));
  521.         return false;
  522.     }
  523.  
  524.     // flush changes
  525.     SCR::Write(.sysconfig.ide, nil);
  526.  
  527.     // flush disc cache before enabling DMA
  528.     if (sync_needed == true)
  529.     {
  530.         y2milestone("Flushing disc cache before enabling DMA...");
  531.         integer exit = (integer) SCR::Execute(.target.bash, "/bin/sync");
  532.  
  533.         if (exit != 0)
  534.         {
  535.         y2warning("Warning: sync failed! (status = %1)", exit);
  536.         }
  537.     }
  538.  
  539.     // activate settings
  540.     if (initscript_needed == true)
  541.     {
  542.         foreach(string dev, string mode, changeDMA, {
  543.             y2milestone("Changing DMA mode:  device=%1 mode=%2", dev, mode);
  544.  
  545.             if (mode != "nochange")
  546.             {
  547.  
  548.             string command = udev_script + " " + dev;
  549.             y2milestone("Starting '%1'", command);
  550.             integer result = (integer) SCR::Execute(.target.bash, command);
  551.  
  552.             if (result != 0)
  553.             {
  554.                 // error message
  555.                 // %1 is string "on", "off" or DMA string mode e.g. "udma5", "mdma2", ...
  556.                 // %2 is device node (e.g. /dev/hdc)
  557.                 Report::Error(sformat(_("An error occurred while activating the changes.\nCannot set required mode '%1' for device %2."), mode, dev));
  558.                 ret = false;
  559.             }
  560.             }
  561.         }
  562.         );
  563.     }
  564.  
  565.     return ret;
  566.     }
  567.  
  568.     /**
  569.      * Set module data
  570.      * @param settings set data from YCP
  571.      * @return void
  572.      */
  573.     global define void Set (list<map<string,any> > settings) ``{
  574.  
  575.     ide_devices = settings;
  576.     return;
  577.     }
  578.  
  579.     /**
  580.      * Get all IDE DMA  settings from the first parameter
  581.      * (For use by autoinstallation.)
  582.      * @param settings The YCP structure to be imported.
  583.      * @return boolean True
  584.      */
  585.     global define boolean Import (list<map<string,any> > settings) ``{
  586.     if (size(settings) == 0)
  587.     {
  588.         return false;
  589.     }
  590.  
  591.     Set(settings);
  592.     return true;
  593.     }
  594.  
  595.     /**
  596.      * Dump the IDE DMA settings to a single map
  597.      * (For use by autoinstallation.)
  598.      * @return list Dumped settings (later acceptable by Import ())
  599.      */
  600.     global define list Export () ``{
  601.     return ide_devices ;
  602.     }
  603.  
  604.     /**
  605.      * Set system configuration without reading values from
  606.      * system - for testing and screenshot mode
  607.      */
  608.     global define void set_test_data() ``{
  609.     ide_devices = [ $["current_dma":"udma2", "dev_name":"/dev/hda",
  610.         "device":"IBM-DJNA-351520", "device_type":"Disk", "dma_setting":"udma2"],
  611.         $["current_dma":"off", "dev_name":"/dev/hdc", "device":"CD-532E-B",
  612.         "device_type":"CD-ROM", "dma_on":"nochange"]
  613.     ];
  614.     }
  615.  
  616.     /**
  617.      * Create rich text description of the current configuration
  618.      * @param all when true all IDE devices are contained in the summary text
  619.      * (even unconfigured devices with default DMA mode)
  620.      * @param richtext select rich/plain text output
  621.      * @return string summary text
  622.      */
  623.     global define string Summary(boolean all, boolean richtext) ``{
  624.     // summary text - header
  625.     string summary = (all == true) ? ((richtext) ? "<P><B>":"") + _("All IDE Devices:") + ((richtext) ? "</B></P>":"\n") : ((richtext) ? "<P><B>":"") + _("Configured Devices:") + ((richtext) ? "</B></P>":"\n");
  626.     string devices = "";
  627.     boolean found = false;
  628.  
  629.     if (size(ide_devices) > 0)
  630.     {
  631.         foreach(map<string, any> dev, ide_devices, ``{
  632.             string dmasetting = (string) (dev["dma_setting"]:nil);
  633.             string devname = (string) (dev["dev_name"]:nil);
  634.  
  635.             if (devname != nil && dmasetting != nil && (all == true || dmasetting != "nochange"))
  636.             {
  637.             // summary text - unknown DMA mode is selected
  638.             devices = devices + ((richtext) ? "<LI><B>":"") + devname + ":" + ((richtext) ? "</B>":"") + " " + sformat("%1 (%2)", dmasetting, mode_names[dmasetting]:_("Unknown mode")) + ((richtext) ? "</LI>":"\n");
  639.             found = true;
  640.             }
  641.         }
  642.         );
  643.     }
  644.  
  645.     // is any device configured?
  646.     if (found == false)
  647.     {
  648.         // summary text - none device is configured
  649.         devices = ((richtext) ? "<LI>":"") + _("No device") + ((richtext) ? "</LI>":"\n");
  650.     }
  651.  
  652.     return summary + ((richtext) ? "<UL>":"") + devices + ((richtext) ? "</UL>":"");
  653.     }
  654.  
  655.  
  656. }
  657.