linux/drivers/s390/scsi/zfcp_unit.c
<<
>>
Prefs
   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}
 264