cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

zfcp_unit.c (6662B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * zfcp device driver
      4 *
      5 * Tracking of manually configured LUNs and helper functions to
      6 * register the LUNs with the SCSI midlayer.
      7 *
      8 * Copyright IBM Corp. 2010
      9 */
     10
     11#include "zfcp_def.h"
     12#include "zfcp_ext.h"
     13
     14/**
     15 * zfcp_unit_scsi_scan - Register LUN with SCSI midlayer
     16 * @unit: The zfcp LUN/unit to register
     17 *
     18 * When the SCSI midlayer is not allowed to automatically scan and
     19 * attach SCSI devices, zfcp has to register the single devices with
     20 * the SCSI midlayer.
     21 */
     22void zfcp_unit_scsi_scan(struct zfcp_unit *unit)
     23{
     24	struct fc_rport *rport = unit->port->rport;
     25	u64 lun;
     26
     27	lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun);
     28
     29	if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
     30		scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, lun,
     31				 SCSI_SCAN_MANUAL);
     32}
     33
     34static void zfcp_unit_scsi_scan_work(struct work_struct *work)
     35{
     36	struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
     37					      scsi_work);
     38
     39	zfcp_unit_scsi_scan(unit);
     40	put_device(&unit->dev);
     41}
     42
     43/**
     44 * zfcp_unit_queue_scsi_scan - Register configured units on port
     45 * @port: The zfcp_port where to register units
     46 *
     47 * After opening a port, all units configured on this port have to be
     48 * registered with the SCSI midlayer. This function should be called
     49 * after calling fc_remote_port_add, so that the fc_rport is already
     50 * ONLINE and the call to scsi_scan_target runs the same way as the
     51 * call in the FC transport class.
     52 */
     53void zfcp_unit_queue_scsi_scan(struct zfcp_port *port)
     54{
     55	struct zfcp_unit *unit;
     56
     57	read_lock_irq(&port->unit_list_lock);
     58	list_for_each_entry(unit, &port->unit_list, list) {
     59		get_device(&unit->dev);
     60		if (scsi_queue_work(port->adapter->scsi_host,
     61				    &unit->scsi_work) <= 0)
     62			put_device(&unit->dev);
     63	}
     64	read_unlock_irq(&port->unit_list_lock);
     65}
     66
     67static struct zfcp_unit *_zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun)
     68{
     69	struct zfcp_unit *unit;
     70
     71	list_for_each_entry(unit, &port->unit_list, list)
     72		if (unit->fcp_lun == fcp_lun) {
     73			get_device(&unit->dev);
     74			return unit;
     75		}
     76
     77	return NULL;
     78}
     79
     80/**
     81 * zfcp_unit_find - Find and return zfcp_unit with specified FCP LUN
     82 * @port: zfcp_port where to look for the unit
     83 * @fcp_lun: 64 Bit FCP LUN used to identify the zfcp_unit
     84 *
     85 * If zfcp_unit is found, a reference is acquired that has to be
     86 * released later.
     87 *
     88 * Returns: Pointer to the zfcp_unit, or NULL if there is no zfcp_unit
     89 *          with the specified FCP LUN.
     90 */
     91struct zfcp_unit *zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun)
     92{
     93	struct zfcp_unit *unit;
     94
     95	read_lock_irq(&port->unit_list_lock);
     96	unit = _zfcp_unit_find(port, fcp_lun);
     97	read_unlock_irq(&port->unit_list_lock);
     98	return unit;
     99}
    100
    101/**
    102 * zfcp_unit_release - Drop reference to zfcp_port and free memory of zfcp_unit.
    103 * @dev: pointer to device in zfcp_unit
    104 */
    105static void zfcp_unit_release(struct device *dev)
    106{
    107	struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
    108
    109	atomic_dec(&unit->port->units);
    110	kfree(unit);
    111}
    112
    113/**
    114 * zfcp_unit_add - add unit to unit list of a port.
    115 * @port: pointer to port where unit is added
    116 * @fcp_lun: FCP LUN of unit to be added
    117 * Returns: 0 success
    118 *
    119 * Sets up some unit internal structures and creates sysfs entry.
    120 */
    121int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
    122{
    123	struct zfcp_unit *unit;
    124	int retval = 0;
    125
    126	mutex_lock(&zfcp_sysfs_port_units_mutex);
    127	if (zfcp_sysfs_port_is_removing(port)) {
    128		/* port is already gone */
    129		retval = -ENODEV;
    130		goto out;
    131	}
    132
    133	unit = zfcp_unit_find(port, fcp_lun);
    134	if (unit) {
    135		put_device(&unit->dev);
    136		retval = -EEXIST;
    137		goto out;
    138	}
    139
    140	unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
    141	if (!unit) {
    142		retval = -ENOMEM;
    143		goto out;
    144	}
    145
    146	unit->port = port;
    147	unit->fcp_lun = fcp_lun;
    148	unit->dev.parent = &port->dev;
    149	unit->dev.release = zfcp_unit_release;
    150	unit->dev.groups = zfcp_unit_attr_groups;
    151	INIT_WORK(&unit->scsi_work, zfcp_unit_scsi_scan_work);
    152
    153	if (dev_set_name(&unit->dev, "0x%016llx",
    154			 (unsigned long long) fcp_lun)) {
    155		kfree(unit);
    156		retval = -ENOMEM;
    157		goto out;
    158	}
    159
    160	if (device_register(&unit->dev)) {
    161		put_device(&unit->dev);
    162		retval = -ENOMEM;
    163		goto out;
    164	}
    165
    166	atomic_inc(&port->units); /* under zfcp_sysfs_port_units_mutex ! */
    167
    168	write_lock_irq(&port->unit_list_lock);
    169	list_add_tail(&unit->list, &port->unit_list);
    170	write_unlock_irq(&port->unit_list_lock);
    171	/*
    172	 * lock order: shost->scan_mutex before zfcp_sysfs_port_units_mutex
    173	 * due to      zfcp_unit_scsi_scan() => zfcp_scsi_slave_alloc()
    174	 */
    175	mutex_unlock(&zfcp_sysfs_port_units_mutex);
    176
    177	zfcp_unit_scsi_scan(unit);
    178	return retval;
    179
    180out:
    181	mutex_unlock(&zfcp_sysfs_port_units_mutex);
    182	return retval;
    183}
    184
    185/**
    186 * zfcp_unit_sdev - Return SCSI device for zfcp_unit
    187 * @unit: The zfcp_unit where to get the SCSI device for
    188 *
    189 * Returns: scsi_device pointer on success, NULL if there is no SCSI
    190 *          device for this zfcp_unit
    191 *
    192 * On success, the caller also holds a reference to the SCSI device
    193 * that must be released with scsi_device_put.
    194 */
    195struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit)
    196{
    197	struct Scsi_Host *shost;
    198	struct zfcp_port *port;
    199	u64 lun;
    200
    201	lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun);
    202	port = unit->port;
    203	shost = port->adapter->scsi_host;
    204	return scsi_device_lookup(shost, 0, port->starget_id, lun);
    205}
    206
    207/**
    208 * zfcp_unit_sdev_status - Return zfcp LUN status for SCSI device
    209 * @unit: The unit to lookup the SCSI device for
    210 *
    211 * Returns the zfcp LUN status field of the SCSI device if the SCSI device
    212 * for the zfcp_unit exists, 0 otherwise.
    213 */
    214unsigned int zfcp_unit_sdev_status(struct zfcp_unit *unit)
    215{
    216	unsigned int status = 0;
    217	struct scsi_device *sdev;
    218	struct zfcp_scsi_dev *zfcp_sdev;
    219
    220	sdev = zfcp_unit_sdev(unit);
    221	if (sdev) {
    222		zfcp_sdev = sdev_to_zfcp(sdev);
    223		status = atomic_read(&zfcp_sdev->status);
    224		scsi_device_put(sdev);
    225	}
    226
    227	return status;
    228}
    229
    230/**
    231 * zfcp_unit_remove - Remove entry from list of configured units
    232 * @port: The port where to remove the unit from the configuration
    233 * @fcp_lun: The 64 bit LUN of the unit to remove
    234 *
    235 * Returns: -EINVAL if a unit with the specified LUN does not exist,
    236 *          0 on success.
    237 */
    238int zfcp_unit_remove(struct zfcp_port *port, u64 fcp_lun)
    239{
    240	struct zfcp_unit *unit;
    241	struct scsi_device *sdev;
    242
    243	write_lock_irq(&port->unit_list_lock);
    244	unit = _zfcp_unit_find(port, fcp_lun);
    245	if (unit)
    246		list_del(&unit->list);
    247	write_unlock_irq(&port->unit_list_lock);
    248
    249	if (!unit)
    250		return -EINVAL;
    251
    252	sdev = zfcp_unit_sdev(unit);
    253	if (sdev) {
    254		scsi_remove_device(sdev);
    255		scsi_device_put(sdev);
    256	}
    257
    258	device_unregister(&unit->dev);
    259
    260	put_device(&unit->dev); /* undo _zfcp_unit_find() */
    261
    262	return 0;
    263}