mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
SCSI fixes on 20231003
Three fixes, all in drivers. The fnic one is the most extensive because the little used user initiated device reset path never tagged the command and adding a tag is rather involved. The other two fixes are smaller and more obvious. Signed-off-by: James E.J. Bottomley <jejb@linux.ibm.com> -----BEGIN PGP SIGNATURE----- iJwEABMIAEQWIQTnYEDbdso9F2cI+arnQslM7pishQUCZRwOQCYcamFtZXMuYm90 dG9tbGV5QGhhbnNlbnBhcnRuZXJzaGlwLmNvbQAKCRDnQslM7pishZvqAQC95+Aa ir6B5iAr5dYXgn31l8LfWuXC0Og4ZhU3o7T/1AEA+nwTu6Jqa+HGbS6ntu3LfEtP J6WaEXlUraHKdf4+Iac= =GNsn -----END PGP SIGNATURE----- Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI fixes from James Bottomley: "Three fixes, all in drivers. The fnic one is the most extensive because the little used user initiated device reset path never tagged the command and adding a tag is rather involved. The other two fixes are smaller and more obvious" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: zfcp: Fix a double put in zfcp_port_enqueue() scsi: fnic: Fix sg_reset success path scsi: target: core: Fix deadlock due to recursive locking
This commit is contained in:
commit
5e62ed3b1c
@ -518,12 +518,12 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
|
||||
if (port) {
|
||||
put_device(&port->dev);
|
||||
retval = -EEXIST;
|
||||
goto err_out;
|
||||
goto err_put;
|
||||
}
|
||||
|
||||
port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);
|
||||
if (!port)
|
||||
goto err_out;
|
||||
goto err_put;
|
||||
|
||||
rwlock_init(&port->unit_list_lock);
|
||||
INIT_LIST_HEAD(&port->unit_list);
|
||||
@ -546,7 +546,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
|
||||
|
||||
if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) {
|
||||
kfree(port);
|
||||
goto err_out;
|
||||
goto err_put;
|
||||
}
|
||||
retval = -EINVAL;
|
||||
|
||||
@ -563,7 +563,8 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
|
||||
|
||||
return port;
|
||||
|
||||
err_out:
|
||||
err_put:
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
err_out:
|
||||
return ERR_PTR(retval);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
#define DRV_NAME "fnic"
|
||||
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
|
||||
#define DRV_VERSION "1.6.0.56"
|
||||
#define DRV_VERSION "1.6.0.57"
|
||||
#define PFX DRV_NAME ": "
|
||||
#define DFX DRV_NAME "%d: "
|
||||
|
||||
@ -237,6 +237,8 @@ struct fnic {
|
||||
unsigned int cq_count;
|
||||
|
||||
struct mutex sgreset_mutex;
|
||||
spinlock_t sgreset_lock; /* lock for sgreset */
|
||||
struct scsi_cmnd *sgreset_sc;
|
||||
struct dentry *fnic_stats_debugfs_host;
|
||||
struct dentry *fnic_stats_debugfs_file;
|
||||
struct dentry *fnic_reset_debugfs_file;
|
||||
|
@ -52,6 +52,8 @@ struct fnic_io_req {
|
||||
unsigned long start_time; /* in jiffies */
|
||||
struct completion *abts_done; /* completion for abts */
|
||||
struct completion *dr_done; /* completion for device reset */
|
||||
unsigned int tag;
|
||||
struct scsi_cmnd *sc; /* midlayer's cmd pointer */
|
||||
};
|
||||
|
||||
enum fnic_port_speeds {
|
||||
|
@ -754,6 +754,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
for (i = 0; i < FNIC_IO_LOCKS; i++)
|
||||
spin_lock_init(&fnic->io_req_lock[i]);
|
||||
|
||||
spin_lock_init(&fnic->sgreset_lock);
|
||||
|
||||
err = -ENOMEM;
|
||||
fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache);
|
||||
if (!fnic->io_req_pool)
|
||||
|
@ -1047,9 +1047,9 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
|
||||
{
|
||||
u8 type;
|
||||
u8 hdr_status;
|
||||
struct fcpio_tag tag;
|
||||
struct fcpio_tag ftag;
|
||||
u32 id;
|
||||
struct scsi_cmnd *sc;
|
||||
struct scsi_cmnd *sc = NULL;
|
||||
struct fnic_io_req *io_req;
|
||||
struct fnic_stats *fnic_stats = &fnic->fnic_stats;
|
||||
struct abort_stats *abts_stats = &fnic->fnic_stats.abts_stats;
|
||||
@ -1058,27 +1058,43 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
|
||||
unsigned long flags;
|
||||
spinlock_t *io_lock;
|
||||
unsigned long start_time;
|
||||
unsigned int tag;
|
||||
|
||||
fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag);
|
||||
fcpio_tag_id_dec(&tag, &id);
|
||||
fcpio_header_dec(&desc->hdr, &type, &hdr_status, &ftag);
|
||||
fcpio_tag_id_dec(&ftag, &id);
|
||||
|
||||
if ((id & FNIC_TAG_MASK) >= fnic->fnic_max_tag_id) {
|
||||
tag = id & FNIC_TAG_MASK;
|
||||
if (tag == fnic->fnic_max_tag_id) {
|
||||
if (!(id & FNIC_TAG_DEV_RST)) {
|
||||
shost_printk(KERN_ERR, fnic->lport->host,
|
||||
"Tag out of range id 0x%x hdr status = %s\n",
|
||||
id, fnic_fcpio_status_to_str(hdr_status));
|
||||
return;
|
||||
}
|
||||
} else if (tag > fnic->fnic_max_tag_id) {
|
||||
shost_printk(KERN_ERR, fnic->lport->host,
|
||||
"Tag out of range tag %x hdr status = %s\n",
|
||||
id, fnic_fcpio_status_to_str(hdr_status));
|
||||
"Tag out of range tag 0x%x hdr status = %s\n",
|
||||
tag, fnic_fcpio_status_to_str(hdr_status));
|
||||
return;
|
||||
}
|
||||
|
||||
sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK);
|
||||
if ((tag == fnic->fnic_max_tag_id) && (id & FNIC_TAG_DEV_RST)) {
|
||||
sc = fnic->sgreset_sc;
|
||||
io_lock = &fnic->sgreset_lock;
|
||||
} else {
|
||||
sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK);
|
||||
io_lock = fnic_io_lock_hash(fnic, sc);
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(!sc);
|
||||
if (!sc) {
|
||||
atomic64_inc(&fnic_stats->io_stats.sc_null);
|
||||
shost_printk(KERN_ERR, fnic->lport->host,
|
||||
"itmf_cmpl sc is null - hdr status = %s tag = 0x%x\n",
|
||||
fnic_fcpio_status_to_str(hdr_status), id);
|
||||
fnic_fcpio_status_to_str(hdr_status), tag);
|
||||
return;
|
||||
}
|
||||
io_lock = fnic_io_lock_hash(fnic, sc);
|
||||
|
||||
spin_lock_irqsave(io_lock, flags);
|
||||
io_req = fnic_priv(sc)->io_req;
|
||||
WARN_ON_ONCE(!io_req);
|
||||
@ -1089,7 +1105,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
|
||||
shost_printk(KERN_ERR, fnic->lport->host,
|
||||
"itmf_cmpl io_req is null - "
|
||||
"hdr status = %s tag = 0x%x sc 0x%p\n",
|
||||
fnic_fcpio_status_to_str(hdr_status), id, sc);
|
||||
fnic_fcpio_status_to_str(hdr_status), tag, sc);
|
||||
return;
|
||||
}
|
||||
start_time = io_req->start_time;
|
||||
@ -1938,6 +1954,10 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic,
|
||||
struct scsi_lun fc_lun;
|
||||
int ret = 0;
|
||||
unsigned long intr_flags;
|
||||
unsigned int tag = scsi_cmd_to_rq(sc)->tag;
|
||||
|
||||
if (tag == SCSI_NO_TAG)
|
||||
tag = io_req->tag;
|
||||
|
||||
spin_lock_irqsave(host->host_lock, intr_flags);
|
||||
if (unlikely(fnic_chk_state_flags_locked(fnic,
|
||||
@ -1964,7 +1984,8 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic,
|
||||
/* fill in the lun info */
|
||||
int_to_scsilun(sc->device->lun, &fc_lun);
|
||||
|
||||
fnic_queue_wq_copy_desc_itmf(wq, scsi_cmd_to_rq(sc)->tag | FNIC_TAG_DEV_RST,
|
||||
tag |= FNIC_TAG_DEV_RST;
|
||||
fnic_queue_wq_copy_desc_itmf(wq, tag,
|
||||
0, FCPIO_ITMF_LUN_RESET, SCSI_NO_TAG,
|
||||
fc_lun.scsi_lun, io_req->port_id,
|
||||
fnic->config.ra_tov, fnic->config.ed_tov);
|
||||
@ -2146,8 +2167,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
|
||||
.ret = SUCCESS,
|
||||
};
|
||||
|
||||
if (new_sc)
|
||||
iter_data.lr_sc = lr_sc;
|
||||
iter_data.lr_sc = lr_sc;
|
||||
|
||||
scsi_host_busy_iter(fnic->lport->host,
|
||||
fnic_pending_aborts_iter, &iter_data);
|
||||
@ -2230,8 +2250,14 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
mutex_lock(&fnic->sgreset_mutex);
|
||||
tag = fnic->fnic_max_tag_id;
|
||||
new_sc = 1;
|
||||
}
|
||||
io_lock = fnic_io_lock_hash(fnic, sc);
|
||||
fnic->sgreset_sc = sc;
|
||||
io_lock = &fnic->sgreset_lock;
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host,
|
||||
"fcid: 0x%x lun: 0x%llx flags: 0x%x tag: 0x%x Issuing sgreset\n",
|
||||
rport->port_id, sc->device->lun, fnic_priv(sc)->flags, tag);
|
||||
} else
|
||||
io_lock = fnic_io_lock_hash(fnic, sc);
|
||||
|
||||
spin_lock_irqsave(io_lock, flags);
|
||||
io_req = fnic_priv(sc)->io_req;
|
||||
|
||||
@ -2247,6 +2273,8 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
}
|
||||
memset(io_req, 0, sizeof(*io_req));
|
||||
io_req->port_id = rport->port_id;
|
||||
io_req->tag = tag;
|
||||
io_req->sc = sc;
|
||||
fnic_priv(sc)->io_req = io_req;
|
||||
}
|
||||
io_req->dr_done = &tm_done;
|
||||
@ -2400,8 +2428,10 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
(u64)sc->cmnd[4] << 8 | sc->cmnd[5]),
|
||||
fnic_flags_and_state(sc));
|
||||
|
||||
if (new_sc)
|
||||
if (new_sc) {
|
||||
fnic->sgreset_sc = NULL;
|
||||
mutex_unlock(&fnic->sgreset_mutex);
|
||||
}
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
|
||||
"Returning from device reset %s\n",
|
||||
|
@ -843,7 +843,6 @@ sector_t target_to_linux_sector(struct se_device *dev, sector_t lb)
|
||||
EXPORT_SYMBOL(target_to_linux_sector);
|
||||
|
||||
struct devices_idr_iter {
|
||||
struct config_item *prev_item;
|
||||
int (*fn)(struct se_device *dev, void *data);
|
||||
void *data;
|
||||
};
|
||||
@ -853,11 +852,9 @@ static int target_devices_idr_iter(int id, void *p, void *data)
|
||||
{
|
||||
struct devices_idr_iter *iter = data;
|
||||
struct se_device *dev = p;
|
||||
struct config_item *item;
|
||||
int ret;
|
||||
|
||||
config_item_put(iter->prev_item);
|
||||
iter->prev_item = NULL;
|
||||
|
||||
/*
|
||||
* We add the device early to the idr, so it can be used
|
||||
* by backend modules during configuration. We do not want
|
||||
@ -867,12 +864,13 @@ static int target_devices_idr_iter(int id, void *p, void *data)
|
||||
if (!target_dev_configured(dev))
|
||||
return 0;
|
||||
|
||||
iter->prev_item = config_item_get_unless_zero(&dev->dev_group.cg_item);
|
||||
if (!iter->prev_item)
|
||||
item = config_item_get_unless_zero(&dev->dev_group.cg_item);
|
||||
if (!item)
|
||||
return 0;
|
||||
mutex_unlock(&device_mutex);
|
||||
|
||||
ret = iter->fn(dev, iter->data);
|
||||
config_item_put(item);
|
||||
|
||||
mutex_lock(&device_mutex);
|
||||
return ret;
|
||||
@ -895,7 +893,6 @@ int target_for_each_device(int (*fn)(struct se_device *dev, void *data),
|
||||
mutex_lock(&device_mutex);
|
||||
ret = idr_for_each(&devices_idr, target_devices_idr_iter, &iter);
|
||||
mutex_unlock(&device_mutex);
|
||||
config_item_put(iter.prev_item);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user