This patchs adds a configure screen for FCP devices (SCSI over Fibrechannel on mainframe) to the gui mode of anaconda and configures the devices so that they are available for partitioning and installation. It also writes a config file /etc/zfcp.conf to the installed system. Missing stuff: - parsing a config file in the linuxrc (should be easy, support for reading /tmp/fcpconfig is already there, it just needs to be written by linuxrc) - verification if valid hex values are entered - booting a zfcp system (tried with a modified initrd, but it seems that the zfcp module takes to long to initialize) - kickstart support Karsten -- Karsten Hopp <karsten@xxxxxxxxx> GPG 1024D/70ABD02C Fingerprint D2D4 3B6B 2DE4 464C A432 210A DFF8 A140 70AB D02C Red Hat Deutschland, Hauptstaetter Str.58 70178 Stuttgart, Tel.+49-711-96437-0, Fax +49-711-96437-111
Index: dispatch.py =================================================================== RCS file: /usr/local/CVS/anaconda/dispatch.py,v retrieving revision 1.107 diff -u -r1.107 dispatch.py --- dispatch.py 17 Mar 2004 23:47:23 -0000 1.107 +++ dispatch.py 20 Jul 2004 12:43:17 -0000 @@ -65,6 +65,7 @@ ("findrootparts", findRootParts, ("intf", "id", "dispatch", "dir", "instPath")), ("findinstall", ("dispatch", "intf", "id", "instPath")), ("installtype", ("dispatch", "id", "method", "intf")), + ("fcpconfig", ("id.fcp", "id.diskset", "intf")), ("partitionmethod", ("id.partitions", "id.instClass")), ("partitionobjinit", partitionObjectsInitialize, ("id.diskset", "id.partitions", Index: fcp.py =================================================================== RCS file: fcp.py diff -N fcp.py --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ fcp.py 20 Jul 2004 12:43:17 -0000 @@ -0,0 +1,156 @@ +# +# fcp.py - mainframe fcp configuration install data +# +# Karsten Hopp <karsten@xxxxxxxxxx> +# +# Copyright 2001-2004 Red Hat, Inc. +# +# This software may be freely redistributed under the terms of the GNU +# library public license. +# +# You should have received a copy of the GNU Library Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +import string +import os +import iutil + +from rhpl.translate import _, N_ +from rhpl.log import log + + +class FCP: + def __init__(self): + self.readConfig() + + # remove the configuration from sysfs, required when the user + # steps backward from the partitioning screen and changes fcp configuration + def cleanFcpSysfs(self, fcpdevices): + if not len(fcpdevices): + return + on = "/sys/bus/ccw/drivers/zfcp/%s/online" + pr = "/sys/bus/ccw/drivers/zfcp/%s/port_remove" + ur = "/sys/bus/ccw/drivers/zfcp/%s/%s/unit_remove" + for i in range(len(fcpdevices)): + fno = on % (fcpdevices[i][0],) + fnp = pr % (fcpdevices[i][0],) + fnu = ur % (fcpdevices[i][0],fcpdevices[i][2],) + try: + fo = open(fno, "w") + except: + continue + else: + log("echo %s > %s" % (0, fno)) + fo.write("0") + fo.close() + try: + fu = open(fnu, "w") + except: + continue + else: + log("echo %s > %s" % (fcpdevices[i][4], fnu)) + fu.write("%s\n" % (fcpdevices[i][4],)) + fu.close() + try: + fp = open(fnp, "w") + except: + continue + else: + log("echo %s > %s" % (fcpdevices[i][2], fnp)) + fp.write("%s\n" % (fcpdevices[i][2],)) + fp.close() + + # initialize devices via sysfs + def writeFcpSysfs(self,fcpdevices): + if not len(fcpdevices): + return + on = "/sys/bus/ccw/drivers/zfcp/%s/online" + pa = "/sys/bus/ccw/drivers/zfcp/%s/port_add" + ua = "/sys/bus/ccw/drivers/zfcp/%s/%s/unit_add" + for i in range(len(fcpdevices)): + fno = on % (fcpdevices[i][0],) + fnp = pa % (fcpdevices[i][0],) + fnu = ua % (fcpdevices[i][0],fcpdevices[i][2],) + try: + fp = open(fnp, "w") + except: + continue + else: + log("echo %s > %s" % (fcpdevices[i][2], fnp)) + fp.write("%s\n" % (fcpdevices[i][2],)) + fp.close() + try: + fu = open(fnu, "w") + except: + continue + else: + log("echo %s > %s" % (fcpdevices[i][4], fnu)) + fu.write("%s\n" % (fcpdevices[i][4],)) + fu.close() + try: + fo = open(fno, "w") + except: + continue + else: + log("echo %s > %s" % (1, fno)) + fo.write("1") + fo.close() + + def write(self, instPath): + if not len(self.fcpdevices): + return + if not os.path.isdir("%s/etc/" %(instPath,)): + iutil.mkdirChain("%s/etc/" %(instPath,)) + + fn = "%s/etc/zfcp.conf" % (instPath,) + f = open(fn, "w") + os.chmod(fn, 0644) + for dev in self.fcpdevices: + f.write("%s %s %s %s %s\n" % (dev[0], dev[1], dev[2], dev[3], dev[4],)) + f.close() + + def writeKS(self,fcpdevices): + # FIXME KH not implemented yet + return + + def readConfig(self): + self.fcpdevices = [] + try: + f = open("/tmp/fcpconfig", "r") + except: + pass + else: + lines = f.readlines() + f.close() + for line in lines: + line = string.strip(line) + fcpconf = string.split(line) + if len(line) > 0 and (len(fcpconf) != 5 or fcpconf[0][:1] == "#"): # nonempty but invalid line or comment + continue + for i in range(1,5): + if fcpconf[i][:2] != "0x": + fcpconf[i] = "0x" + fcpconf[i] + fcpconf[4] = self.expandLun(fcpconf[4]) + self.fcpdevices.append(fcpconf) + + def sanityCheckHexValue(self, length, value): + # FIXME: do a real checking if this is a valid hex value + if len(value) == length: + return None + else: + return _("Invalid input. Entered string must have %d characters") % length + + # FCP LUNs are usually entered as 16 bit, sysfs accepts only 64 bit + # (#125632), expand with zeroes if necessary + def expandLun(self, lun): + if lun[:2] == "0x": + lun = lun[2:] + lun = "0x" + "0" * (4 - len(lun)) + lun + length = len(lun) - 2 + lun = lun + "0" * (16 - len(lun) + 2) + return lun + + +# vim:tw=78:ts=4:et:sw=4 Index: gui.py =================================================================== RCS file: /usr/local/CVS/anaconda/gui.py,v retrieving revision 1.372 diff -u -r1.372 gui.py --- gui.py 21 Jun 2004 18:51:17 -0000 1.372 +++ gui.py 20 Jul 2004 12:43:17 -0000 @@ -47,6 +47,7 @@ "mouse" : ("mouse_gui", "MouseWindow"), "welcome" : ("welcome_gui", "WelcomeWindow"), "installtype" : ("installpath_gui", "InstallPathWindow"), + "fcpconfig" : ("fcp_gui", "FCPWindow"), "partitionmethod" : ("partmethod_gui", "PartitionMethodWindow"), "partition" : ("partition_gui", "PartitionWindow"), "autopartition" : ("partition_gui", "AutoPartitionWindow"), Index: installclass.py =================================================================== RCS file: /usr/local/CVS/anaconda/installclass.py,v retrieving revision 1.218 diff -u -r1.218 installclass.py --- installclass.py 9 Jul 2004 10:01:52 -0000 1.218 +++ installclass.py 20 Jul 2004 12:43:17 -0000 @@ -124,6 +124,7 @@ "findrootparts", "betanag", "installtype", + "fcpconfig", "partitionmethod", "partitionobjinit", "partitionmethodsetup", @@ -169,6 +170,9 @@ if not BETANAG: dispatch.skipStep("betanag", permanent=1) + if iutil.getArch() != "s390": + dispatch.skipStep("fcpconfig") + if iutil.getArch() != "i386" or 1: dispatch.skipStep("bootdisk") @@ -358,7 +362,11 @@ def setSELinux(self, id, sel): id.security.setSELinux(sel) + def setFCP(self, id, fcpdev): + id.fcp.fcpdevices = fcpdev + def setFirewall(self, id, enable = 1, trusts = [], ports = []): + ssh = 0, telnet = 0, smtp = 0, http = 0, ftp = 0): id.firewall.enabled = enable id.firewall.trustdevs = trusts # this is a little ugly, but we want to let setting a service Index: instdata.py =================================================================== RCS file: /usr/local/CVS/anaconda/instdata.py,v retrieving revision 1.55 diff -u -r1.55 instdata.py --- instdata.py 7 May 2004 17:26:25 -0000 1.55 +++ instdata.py 20 Jul 2004 12:43:17 -0000 @@ -27,6 +27,7 @@ import partitions import partedUtils import hdrlist +import fcp from flags import * from constants import * @@ -57,6 +58,7 @@ self.langSupport = language.Language() self.instClass = None self.network = network.Network() + self.fcp = fcp.FCP() self.firewall = firewall.Firewall() self.security = security.Security() self.timezone = timezone.Timezone() @@ -119,6 +121,7 @@ self.timezone.write (instPath) self.auth.write (instPath) self.firewall.write (instPath) + self.fcp.write (instPath) self.security.write (instPath) self.rootPassword.write (instPath, self.auth) self.accounts.write (instPath, self.auth) @@ -172,6 +175,7 @@ self.keyboard.writeKS(f) self.xsetup.writeKS(f, self.desktop) self.network.writeKS(f) + self.fcp.writeKS(f) self.rootPassword.writeKS(f, self.auth) self.firewall.writeKS(f) self.security.writeKS(f) Index: kickstart.py =================================================================== RCS file: /usr/local/CVS/anaconda/kickstart.py,v retrieving revision 1.236 diff -u -r1.236 kickstart.py --- kickstart.py 9 Jul 2004 21:45:40 -0000 1.236 +++ kickstart.py 20 Jul 2004 12:43:18 -0000 @@ -174,6 +174,10 @@ sel = 2 self.setSELinux(id, sel) + + # FIXME KH add FCP support + def doFCP(self, id, args): + return def doAuthconfig(self, id, args): (args, extra) = isys.getopt(args, '', Index: partedUtils.py =================================================================== RCS file: /usr/local/CVS/anaconda/partedUtils.py,v retrieving revision 1.63 diff -u -r1.63 partedUtils.py --- partedUtils.py 13 Jul 2004 20:21:27 -0000 1.63 +++ partedUtils.py 20 Jul 2004 12:43:18 -0000 @@ -4,6 +4,7 @@ # Matt Wilson <msw@xxxxxxxxxx> # Jeremy Katz <katzj@xxxxxxxxxx> # Mike Fulbright <msf@xxxxxxxxxx> +# Karsten Hopp <karsten@xxxxxxxxxx> # # Copyright 2002-2003 Red Hat, Inc. # @@ -817,7 +818,7 @@ DiskSet.skippedDisks.append(drive) continue # FIXME: need the right fix for z/VM formatted dasd - if iutil.getArch() == "s390" and isys.getDasdState(drive): + if iutil.getArch() == "s390" and drive[:4] == "dasd" and isys.getDasdState(drive): devs = isys.getDasdDevPort() rc = intf.messageWindow(_("Warning"), _("The partition table on device %s (%s) was unreadable. " @@ -845,7 +846,7 @@ if (initAll and ((clearDevs is None) or (len(clearDevs) == 0) or drive in clearDevs) and not flags.test): - if iutil.getArch() == "s390": + if iutil.getArch() == "s390" and drive[:4] == "dasd": if (self.dasdFmt(intf, drive)): DiskSet.skippedDisks.append(drive) continue @@ -880,11 +881,11 @@ _("The partition table on device %s was unreadable. " "To create new partitions it must be initialized, " "causing the loss of ALL DATA on this drive.\n\n" - "This operation will override any previous " - "installation choices about which drives to " - "ignore.\n\n" + "This operation will override any previous " + "installation choices about which drives to " + "ignore.\n\n" "Would you like to initialize this drive, " - "erasing ALL DATA?") + "erasing ALL DATA?") % (format,), type = "yesno") if rc == 0: DiskSet.skippedDisks.append(drive) @@ -893,7 +894,7 @@ recreate = 1 if recreate == 1 and not flags.test: - if iutil.getArch() == "s390": + if iutil.getArch() == "s390" and drive[:4] == "dasd": if (self.dasdFmt(intf, drive)): DiskSet.skippedDisks.append(drive) continue @@ -919,7 +920,7 @@ DiskSet.skippedDisks.append(drive) continue elif ret == -1: - if iutil.getArch() == "s390": + if iutil.getArch() == "s390" and drive[:4] == "dasd": if (self.dasdFmt(intf, drive)): DiskSet.skippedDisks.append(drive) continue Index: iw/fcp_gui.py =================================================================== RCS file: iw/fcp_gui.py diff -N iw/fcp_gui.py --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ iw/fcp_gui.py 20 Jul 2004 12:43:18 -0000 @@ -0,0 +1,275 @@ +# +# zfcp_gui.py: mainframe FCP configuration dialog +# +# Karsten Hopp <karsten@xxxxxxxxxx> +# +# Copyright 2000-2004 Red Hat, Inc. +# +# This software may be freely redistributed under the terms of the GNU +# library public license. +# +# You should have received a copy of the GNU Library Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +import gtk +import gobject +from iw_gui import * +import gui +from rhpl.translate import _, N_ +import os + +class FCPWindow(InstallWindow): + + windowTitle = N_("FCP Configuration") + htmlTag = "fcpconf" + + def __init__(self, ics): + InstallWindow.__init__(self, ics) + self.options = [(_("Device number"), 1, self.handleInvalidDevice), + (_("SCSI Id"), 0, self.handleInvalidSCSIId), + (_("WWPN"), 1, self.handleInvalidWWPN), + (_("SCSI LUN"), 0, self.handleInvalidSCSILun), + (_("FCP LUN"), 1, self.handleInvalidFCPLun)] + + def getNext(self): + self.fcp.writeFcpSysfs(self.fcpdevices) + isys.flushDriveDict() + self.diskset.refreshDevices(self.intf) + try: + iutil.makeDriveDeviceNodes() + except: + pass + + def handleInvalidDevice(self): + self.intf.messageWindow(_("Error With Data"), + _("You have not specified a device number or the number is invalid")) + + def handleInvalidSCSIId(self): + self.intf.messageWindow(_("Error With Data"), + _("You have not specified a SCSI ID or the ID is invalid.")) + + def handleInvalidWWPN(self): + self.intf.messageWindow(_("Error With Data"), + _("You have not specified a worldwide port name or the name is invalid.")) + + def handleInvalidSCSILun(self): + self.intf.messageWindow(_("Error With Data"), + _("You have not specified a SCSI LUN or the number is invalid.")) + + def handleInvalidFCPLun(self): + self.intf.messageWindow(_("Error With Data"), + _("You have not specified a FCP LUN or the number is invalid.")) + + def setupDevices(self): + self.store = gtk.TreeStore(gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING) + + self.view = gtk.TreeView(self.store) + for i in range(len(self.options)): + if self.options[i][1] == 1: + renderer = gtk.CellRendererText() + column = gtk.TreeViewColumn(self.options[i][0], renderer, text=i) + column.set_clickable(gtk.FALSE) + column.set_min_width(140) + column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE) + self.view.append_column(column) + for i in range(len(self.fcpdevices)): + self.store.append(None, (self.fcpdevices[i][0],self.fcpdevices[i][1], \ + self.fcpdevices[i][2],self.fcpdevices[i][3],self.fcpdevices[i][4])) + + self.ignoreEvents = 1 + iter = self.store.get_iter_first() + selection = self.view.get_selection() + selection.set_mode(gtk.SELECTION_BROWSE) + if iter != None: + selection.select_iter(iter) + self.ignoreEvents = 0 + return self.view + + + # FCPWindow tag="fcpconf" + def getScreen(self, fcp, diskset, intf): + self.diskset = diskset + self.intf = intf + box = gtk.VBox(gtk.FALSE) + box.set_border_width(6) + fcp.cleanFcpSysfs(fcp.fcpdevices) + self.fcp = fcp + self.fcpdevices = fcp.fcpdevices + + devvbox = gtk.VBox(gtk.FALSE) + + self.devlist = self.setupDevices() + + devlistSW = gtk.ScrolledWindow() + devlistSW.set_border_width(6) + devlistSW.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + devlistSW.set_shadow_type(gtk.SHADOW_IN) + devlistSW.add(self.devlist) + devlistSW.set_size_request(-1, 350) + devvbox.pack_start(devlistSW, gtk.FALSE, padding=10) + + buttonbar = gtk.HButtonBox() + buttonbar.set_layout(gtk.BUTTONBOX_START) + buttonbar.set_border_width(6) + add = gtk.Button(_("_Add")) + add.connect("clicked", self.addDevice) + buttonbar.pack_start(add, gtk.FALSE) + edit = gtk.Button(_("_Edit")) + edit.connect("clicked", self.editDevice) + buttonbar.pack_start(edit, gtk.FALSE) + remove = gtk.Button(_("_Remove")) + remove.connect("clicked", self.removeDevice) + buttonbar.pack_start(remove, gtk.FALSE) + devvbox.pack_start(buttonbar, gtk.FALSE) + + devvbox.set_border_width(12) + l = gtk.Label() + l.set_markup("<b>%s</b>" %(_("FCP Devices"),)) + frame=gtk.Frame() + frame.set_label_widget(l) + frame.add(devvbox) + frame.set_shadow_type(gtk.SHADOW_NONE) + box.pack_start(frame, gtk.FALSE) + return box + + + def addDevice(self, data): + if self.ignoreEvents: + return + addWin = gtk.Dialog(_("Add FCP device"), + flags=gtk.DIALOG_MODAL) + gui.addFrame(addWin) + addWin.set_modal(gtk.TRUE) + addWin.set_position (gtk.WIN_POS_CENTER) + devbox = gtk.VBox() + fcpTable = gtk.Table(len(self.options), 2) + entrys = {} + for t in range(len(self.options)): + label = gtk.Label("%s:" %(self.options[t][0],)) + label.set_alignment(0.0, 0.5) + label.set_property("use-underline", gtk.TRUE) + fcpTable.attach(label, 0, 1, t, t+1, gtk.FILL, 0, 10) + entrys[t] = gtk.Entry(18) + fcpTable.attach(entrys[t], 1, 2, t, t+1, gtk.FILL, 0, 10) + + devbox.pack_start(fcpTable, gtk.FALSE, gtk.FALSE, 6) + devbox.set_border_width(6) + frame = gtk.Frame() + frame.set_border_width(12) + frame.add(devbox) + frame.set_shadow_type(gtk.SHADOW_NONE) + addWin.vbox.pack_start(frame, padding=6) + addWin.set_position(gtk.WIN_POS_CENTER) + addWin.show_all() + addWin.add_button('gtk-cancel', 2) + addWin.add_button('gtk-ok', 1) + tmpvals = {} + while 1: + invalid = 0 + rc = addWin.run() + if rc == 1: + for t in range(len(self.options)): + tmpvals[t] = entrys[t].get_text() + if tmpvals[t] == "": + self.options[t][2]() # FIXME: This hides addWin behind the main window + invalid = 1 + break + if t != 0 and tmpvals[t][:2] != "0x": + tmpvals[t] = "0x" + tmpvals[t] + elif t == 0: + tmpvals[t] = "0" * (4 - len(tmpvals[t])) + tmpvals[t] + if tmpvals[t][:4] != "0.0.": + tmpvals[t] = "0.0." + tmpvals[t] + + if invalid == 0: + addWin.destroy() + tmpvals[4] = self.fcp.expandLun(tmpvals[4]) + line = self.store.append(None, (tmpvals[0],tmpvals[1],tmpvals[2],tmpvals[3],tmpvals[4])) + self.fcpdevices.append(tmpvals) + break + if rc == 2: + addWin.destroy() + break + return + + def editDevice(self, data): + if self.ignoreEvents: + return + selection = self.view.get_selection() + (model, iter) = selection.get_selected() + if not iter: + return None + devicenum = model.get_value(iter, 0) + scsiid = model.get_value(iter, 1) + wwpn = model.get_value(iter, 2) + scsilun = model.get_value(iter, 3) + fcplun = model.get_value(iter, 4) + + # create dialog box + editWin = gtk.Dialog(_("Edit FCP device %s") % (devicenum,), + flags=gtk.DIALOG_MODAL) + gui.addFrame(editWin) + editWin.set_modal(gtk.TRUE) + editWin.set_position (gtk.WIN_POS_CENTER) + devbox = gtk.VBox() + fcpTable = gtk.Table(len(self.options), 2) + entrys = {} + for t in range(len(self.options)): + label = gtk.Label("%s:" %(self.options[t][0],)) + label.set_alignment(0.0, 0.5) + label.set_property("use-underline", gtk.TRUE) + fcpTable.attach(label, 0, 1, t, t+1, gtk.FILL, 0, 10) + entrys[t] = gtk.Entry(18) + entrys[t].set_text(model.get_value(iter, t)) + fcpTable.attach(entrys[t], 1, 2, t, t+1, gtk.FILL, 0, 10) + devbox.pack_start(fcpTable, gtk.FALSE, gtk.FALSE, 6) + devbox.set_border_width(6) + frame = gtk.Frame() + frame.set_border_width(12) + frame.add(devbox) + frame.set_shadow_type(gtk.SHADOW_NONE) + editWin.vbox.pack_start(frame, padding=6) + editWin.set_position(gtk.WIN_POS_CENTER) + editWin.show_all() + editWin.add_button('gtk-cancel', 2) + editWin.add_button('gtk-ok', 1) + tmpvals = {} + while 1: + invalid = 0 + rc = editWin.run() + if rc == 2: + editWin.destroy() + return + if rc == 1: + for t in range(len(self.options)): + tmpvals[t] = entrys[t].get_text() + if tmpvals[t] == "": + self.options[t][2]() # FIXME: This hides addWin behind the main window + invalid = 1 + break + if invalid == 0: + editWin.destroy() + for t in range(len(self.options)): + self.store.set_value(iter, t, tmpvals[t]) + break + return + + def removeDevice(self, data): + selection = self.view.get_selection() + (model, iter) = selection.get_selected() + if not iter: + return None + rc = self.intf.messageWindow(_("Warning"), + _("You're about to remove a FCP disk from your " + "configuration. Are you sure that you wish " + "to continue?"), type = "yesno") + if rc == 1: + self.store.remove(iter) + return + +# vim:tw=78:ts=4:et:sw=4
Attachment:
pgpT6yfT6rjiV.pgp
Description: PGP signature