Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions package/yast2-s390.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
-------------------------------------------------------------------
Mon Jun 5 10:09:02 UTC 2023 - José Iván López González <jlopez@suse.com>

- Expose zFCP core functionallity (related to
gh#openSUSUE/agama#594)
- 4.6.2

-------------------------------------------------------------------
Wed May 10 13:35:34 UTC 2023 - Stefan Hundhammer <shundhammer@suse.com>

Expand Down
2 changes: 1 addition & 1 deletion package/yast2-s390.spec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


Name: yast2-s390
Version: 4.6.1
Version: 4.6.2
Release: 0
Group: System/YaST
License: GPL-2.0-only
Expand Down
183 changes: 183 additions & 0 deletions src/lib/y2s390/zfcp.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Copyright (c) [2023] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "yast"
require "yaml"

module Y2S390
# Manager for zFCP devices
class ZFCP
include Yast
include Yast::Logger

# Detected controllers
#
# @return [Array<Hash>] keys for each hash:
# "sysfs_bus_id", "resource"
attr_reader :controllers

# Detected LUN disks
#
# @return [Array<Hash>] keys for each hash:
# "dev_name", "detail", "vendor", "device" and "io".
attr_reader :disks

def initialize
@controllers = []
@disks = []
end

# Probes the zFCP controllers
def probe_controllers
make_all_devices_visible

storage_devices = Yast::SCR.Read(path(".probe.storage"))
controllers = storage_devices.select { |i| i["device"] == "zFCP controller" }

@controllers = controllers.map { |c| c.slice("sysfs_bus_id", "resource") }
end

# Probes the zFCP disks
def probe_disks
storage_disks = read_mock_disks || Yast::SCR.Read(path(".probe.disk"))
zfcp_disks = storage_disks.select { |d| d["driver"] == "zfcp" }

tapes = Yast::SCR.Read(path(".probe.tape"))
scsi_tapes = tapes.select { |t| t["bus"] == "SCSI" }

disks = zfcp_disks + scsi_tapes

@disks = disks.map { |d| d.slice("dev_name", "detail", "vendor", "device", "io") }
end

# Runs the command for activating a controller
#
# @note All LUNs are automatically activated if "allow_lun_scan" is active, see
# https://www.ibm.com/docs/en/linux-on-systems?topic=wsd-configuring-devices.
#
# @param channel [String] E.g., "0.0.fa00"
# @return [Hash] See {#run}. The exit code corresponds to the chzdev one.
def activate_controller(channel)
command = format("/sbin/zfcp_host_configure '%s' %d", channel, 1)
run(command)
end

# Whether the controller is activated
#
# @param channel [String] E.g., "0.0.fa00"
# @return [Boolean]
def activated_controller?(channel)
controller = controllers.find { |c| c["sysfs_bus_id"] == channel }
return false unless controller

io = controller.dig("resource", "io") || []
io.any? { |i| i["active"] }
end

# Runs the command for activating a zFCP disk
#
# @param channel [String] E.g., "0.0.fa00"
# @param wwpn [String] E.g., "0x500507630708d3b3"
# @param lun [String] E.g., "0x0013000000000000"
#
# @return [Hash] See {#run}. The exit code corresponds to the chzdev one.
def activate_disk(channel, wwpn, lun)
command = format("/sbin/zfcp_disk_configure '%s' '%s' '%s' %d", channel, wwpn, lun, 1)
run(command)
end

# Runs the command for deactivating a zFCP disk
#
# @note Deactivate fails if "allow_lun_scan" is active, see
# https://www.ibm.com/docs/en/linux-on-systems?topic=wsd-configuring-devices.
#
# @param channel [String] E.g., "0.0.fa00"
# @param wwpn [String] E.g., "0x500507630708d3b3"
# @param lun [String] E.g., "0x0013000000000000"
#
# @return [Hash] See {#run}. The exit code corresponds to the chzdev one.
Comment thread
dgdavid marked this conversation as resolved.
def deactivate_disk(channel, wwpn, lun)
command = format("/sbin/zfcp_disk_configure '%s' '%s' '%s' %d", channel, wwpn, lun, 0)
run(command)
end

# Runs the command for finding WWPNs
#
# @param channel [String] E.g., "0.0.fa00"
# @return [Hash] See {#run}
def find_wwpns(channel)
command = format("zfcp_san_disc -b '%s' -W", channel)
run(command)
end

# Runs the command for finding LUNs
#
# @param channel [String] E.g., "0.0.fa00"
# @param wwpn [String] E.g., "0x500507630708d3b3"
#
# @return [Hash] See {#run}
def find_luns(channel, wwpn)
command = format("zfcp_san_disc -b '%s' -p '%s' -L", channel, wwpn)
run(command)
end

private

# Sets all detected controllers as visible
def make_all_devices_visible
# Checking if it is a z/VM and evaluating all FCP controllers in order to activate
output = run("/sbin/vmcp q v fcp")
return if output["exit"] != 0

fcp_lines = output["stdout"].map(&:split).select { |l| l.first == "FCP" }
devices = fcp_lines.map { |l| l[1].downcase }

# Remove all needed devices from CIO device driver blacklist in order to see it
devices.each do |device|
log.info "Removing #{device} from the CIO device driver blacklist"
run("/sbin/cio_ignore -r #{device}")
end
end

# Runs the given command
#
# @param command [String]
# @return [Hash] Output of the command which has these keys: "exit", "stdout", "stderr".
def run(command)
Yast::SCR.Execute(path(".target.bash_output"), command).tap do |output|
log.info("command #{command} output #{output}")

output["exit"] = output["exit"].to_i
output["stdout"] = output["stdout"].split("\n").reject(&:empty?)
end
end

# Reads the mock disks from the YAML file pointed by YAST2_S390_PROBE_DISK
#
# Suggestion: YAST2_S390_PROBE_DISK=test/data/probe_disk.yml rake run[zfcp]
#
# @return [Array<Hash>, nil] List of mocked LUN disks or nil if no file found
def read_mock_disks
mock_filename = ENV["YAST2_S390_PROBE_DISK"]
return nil unless mock_filename

YAML.safe_load(File.read(mock_filename))
end
end
end
Loading