mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 05:32:00 +00:00
SCSI misc on 20221222
Mostly small bug fixes and small updates. The only things of note is a qla2xxx fix for crash on hotplug and timeout and the addition of a user exposed abstraction layer for persistent reservation error return handling (which necessitates the conversion of nvme.c as well as SCSI). Signed-off-by: James E.J. Bottomley <jejb@linux.ibm.com> -----BEGIN PGP SIGNATURE----- iJwEABMIAEQWIQTnYEDbdso9F2cI+arnQslM7pishQUCY6SZISYcamFtZXMuYm90 dG9tbGV5QGhhbnNlbnBhcnRuZXJzaGlwLmNvbQAKCRDnQslM7pishQkdAP9Juri0 ihkyA9tVx1ZslVOp8V8mWK3P2VROA4ArvcMRVwD/Qxf2REP8Fx2GIgC0sNaRedg3 +ncveg3EpZ1n/NXXeDw= =q+XO -----END PGP SIGNATURE----- Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull more SCSI updates from James Bottomley: "Mostly small bug fixes and small updates. The only things of note is a qla2xxx fix for crash on hotplug and timeout and the addition of a user exposed abstraction layer for persistent reservation error return handling (which necessitates the conversion of nvme.c as well as SCSI)" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: qla2xxx: Fix crash when I/O abort times out nvme: Convert NVMe errors to PR errors scsi: sd: Convert SCSI errors to PR errors scsi: core: Rename status_byte to sg_status_byte block: Add error codes for common PR failures scsi: sd: sd_zbc: Trace zone append emulation scsi: libfc: Include the correct header
This commit is contained in:
commit
8395ae05cb
@ -2117,11 +2117,34 @@ static int nvme_send_ns_pr_command(struct nvme_ns *ns, struct nvme_command *c,
|
||||
return nvme_submit_sync_cmd(ns->queue, c, data, 16);
|
||||
}
|
||||
|
||||
static int nvme_sc_to_pr_err(int nvme_sc)
|
||||
{
|
||||
if (nvme_is_path_error(nvme_sc))
|
||||
return PR_STS_PATH_FAILED;
|
||||
|
||||
switch (nvme_sc) {
|
||||
case NVME_SC_SUCCESS:
|
||||
return PR_STS_SUCCESS;
|
||||
case NVME_SC_RESERVATION_CONFLICT:
|
||||
return PR_STS_RESERVATION_CONFLICT;
|
||||
case NVME_SC_ONCS_NOT_SUPPORTED:
|
||||
return -EOPNOTSUPP;
|
||||
case NVME_SC_BAD_ATTRIBUTES:
|
||||
case NVME_SC_INVALID_OPCODE:
|
||||
case NVME_SC_INVALID_FIELD:
|
||||
case NVME_SC_INVALID_NS:
|
||||
return -EINVAL;
|
||||
default:
|
||||
return PR_STS_IOERR;
|
||||
}
|
||||
}
|
||||
|
||||
static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
|
||||
u64 key, u64 sa_key, u8 op)
|
||||
{
|
||||
struct nvme_command c = { };
|
||||
u8 data[16] = { 0, };
|
||||
int ret;
|
||||
|
||||
put_unaligned_le64(key, &data[0]);
|
||||
put_unaligned_le64(sa_key, &data[8]);
|
||||
@ -2131,8 +2154,14 @@ static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
|
||||
|
||||
if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
|
||||
bdev->bd_disk->fops == &nvme_ns_head_ops)
|
||||
return nvme_send_ns_head_pr_command(bdev, &c, data);
|
||||
return nvme_send_ns_pr_command(bdev->bd_disk->private_data, &c, data);
|
||||
ret = nvme_send_ns_head_pr_command(bdev, &c, data);
|
||||
else
|
||||
ret = nvme_send_ns_pr_command(bdev->bd_disk->private_data, &c,
|
||||
data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return nvme_sc_to_pr_err(ret);
|
||||
}
|
||||
|
||||
static int nvme_pr_register(struct block_device *bdev, u64 old,
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
@ -110,6 +110,7 @@ static void qla24xx_abort_iocb_timeout(void *data)
|
||||
struct qla_qpair *qpair = sp->qpair;
|
||||
u32 handle;
|
||||
unsigned long flags;
|
||||
int sp_found = 0, cmdsp_found = 0;
|
||||
|
||||
if (sp->cmd_sp)
|
||||
ql_dbg(ql_dbg_async, sp->vha, 0x507c,
|
||||
@ -124,18 +125,21 @@ static void qla24xx_abort_iocb_timeout(void *data)
|
||||
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
|
||||
for (handle = 1; handle < qpair->req->num_outstanding_cmds; handle++) {
|
||||
if (sp->cmd_sp && (qpair->req->outstanding_cmds[handle] ==
|
||||
sp->cmd_sp))
|
||||
sp->cmd_sp)) {
|
||||
qpair->req->outstanding_cmds[handle] = NULL;
|
||||
cmdsp_found = 1;
|
||||
}
|
||||
|
||||
/* removing the abort */
|
||||
if (qpair->req->outstanding_cmds[handle] == sp) {
|
||||
qpair->req->outstanding_cmds[handle] = NULL;
|
||||
sp_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
|
||||
|
||||
if (sp->cmd_sp) {
|
||||
if (cmdsp_found && sp->cmd_sp) {
|
||||
/*
|
||||
* This done function should take care of
|
||||
* original command ref: INIT
|
||||
@ -143,8 +147,10 @@ static void qla24xx_abort_iocb_timeout(void *data)
|
||||
sp->cmd_sp->done(sp->cmd_sp, QLA_OS_TIMER_EXPIRED);
|
||||
}
|
||||
|
||||
abt->u.abt.comp_status = cpu_to_le16(CS_TIMEOUT);
|
||||
sp->done(sp, QLA_OS_TIMER_EXPIRED);
|
||||
if (sp_found) {
|
||||
abt->u.abt.comp_status = cpu_to_le16(CS_TIMEOUT);
|
||||
sp->done(sp, QLA_OS_TIMER_EXPIRED);
|
||||
}
|
||||
}
|
||||
|
||||
static void qla24xx_abort_sp_done(srb_t *sp, int res)
|
||||
|
@ -376,7 +376,7 @@ static int scsi_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
|
||||
* fill in all the output members
|
||||
*/
|
||||
hdr->status = scmd->result & 0xff;
|
||||
hdr->masked_status = status_byte(scmd->result);
|
||||
hdr->masked_status = sg_status_byte(scmd->result);
|
||||
hdr->msg_status = COMMAND_COMPLETE;
|
||||
hdr->host_status = host_byte(scmd->result);
|
||||
hdr->driver_status = 0;
|
||||
|
@ -1709,6 +1709,36 @@ static char sd_pr_type(enum pr_type type)
|
||||
}
|
||||
};
|
||||
|
||||
static int sd_scsi_to_pr_err(struct scsi_sense_hdr *sshdr, int result)
|
||||
{
|
||||
switch (host_byte(result)) {
|
||||
case DID_TRANSPORT_MARGINAL:
|
||||
case DID_TRANSPORT_DISRUPTED:
|
||||
case DID_BUS_BUSY:
|
||||
return PR_STS_RETRY_PATH_FAILURE;
|
||||
case DID_NO_CONNECT:
|
||||
return PR_STS_PATH_FAILED;
|
||||
case DID_TRANSPORT_FAILFAST:
|
||||
return PR_STS_PATH_FAST_FAILED;
|
||||
}
|
||||
|
||||
switch (status_byte(result)) {
|
||||
case SAM_STAT_RESERVATION_CONFLICT:
|
||||
return PR_STS_RESERVATION_CONFLICT;
|
||||
case SAM_STAT_CHECK_CONDITION:
|
||||
if (!scsi_sense_valid(sshdr))
|
||||
return PR_STS_IOERR;
|
||||
|
||||
if (sshdr->sense_key == ILLEGAL_REQUEST &&
|
||||
(sshdr->asc == 0x26 || sshdr->asc == 0x24))
|
||||
return -EINVAL;
|
||||
|
||||
fallthrough;
|
||||
default:
|
||||
return PR_STS_IOERR;
|
||||
}
|
||||
}
|
||||
|
||||
static int sd_pr_command(struct block_device *bdev, u8 sa,
|
||||
u64 key, u64 sa_key, u8 type, u8 flags)
|
||||
{
|
||||
@ -1737,7 +1767,10 @@ static int sd_pr_command(struct block_device *bdev, u8 sa,
|
||||
scsi_print_sense_hdr(sdev, NULL, &sshdr);
|
||||
}
|
||||
|
||||
return result;
|
||||
if (result <= 0)
|
||||
return result;
|
||||
|
||||
return sd_scsi_to_pr_err(&sshdr, result);
|
||||
}
|
||||
|
||||
static int sd_pr_register(struct block_device *bdev, u64 old_key, u64 new_key,
|
||||
|
84
drivers/scsi/sd_trace.h
Normal file
84
drivers/scsi/sd_trace.h
Normal file
@ -0,0 +1,84 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2022 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM sd
|
||||
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE sd_trace
|
||||
|
||||
#if !defined(_SD_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
TRACE_EVENT(scsi_prepare_zone_append,
|
||||
|
||||
TP_PROTO(struct scsi_cmnd *cmnd, sector_t lba,
|
||||
unsigned int wp_offset),
|
||||
|
||||
TP_ARGS(cmnd, lba, wp_offset),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, host_no )
|
||||
__field( unsigned int, channel )
|
||||
__field( unsigned int, id )
|
||||
__field( unsigned int, lun )
|
||||
__field( sector_t, lba )
|
||||
__field( unsigned int, wp_offset )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->host_no = cmnd->device->host->host_no;
|
||||
__entry->channel = cmnd->device->channel;
|
||||
__entry->id = cmnd->device->id;
|
||||
__entry->lun = cmnd->device->lun;
|
||||
__entry->lba = lba;
|
||||
__entry->wp_offset = wp_offset;
|
||||
),
|
||||
|
||||
TP_printk("host_no=%u, channel=%u id=%u lun=%u lba=%llu wp_offset=%u",
|
||||
__entry->host_no, __entry->channel, __entry->id,
|
||||
__entry->lun, __entry->lba, __entry->wp_offset)
|
||||
);
|
||||
|
||||
TRACE_EVENT(scsi_zone_wp_update,
|
||||
|
||||
TP_PROTO(struct scsi_cmnd *cmnd, sector_t rq_sector,
|
||||
unsigned int wp_offset, unsigned int good_bytes),
|
||||
|
||||
TP_ARGS(cmnd, rq_sector, wp_offset, good_bytes),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, host_no )
|
||||
__field( unsigned int, channel )
|
||||
__field( unsigned int, id )
|
||||
__field( unsigned int, lun )
|
||||
__field( sector_t, rq_sector )
|
||||
__field( unsigned int, wp_offset )
|
||||
__field( unsigned int, good_bytes )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->host_no = cmnd->device->host->host_no;
|
||||
__entry->channel = cmnd->device->channel;
|
||||
__entry->id = cmnd->device->id;
|
||||
__entry->lun = cmnd->device->lun;
|
||||
__entry->rq_sector = rq_sector;
|
||||
__entry->wp_offset = wp_offset;
|
||||
__entry->good_bytes = good_bytes;
|
||||
),
|
||||
|
||||
TP_printk("host_no=%u, channel=%u id=%u lun=%u rq_sector=%llu" \
|
||||
" wp_offset=%u good_bytes=%u",
|
||||
__entry->host_no, __entry->channel, __entry->id,
|
||||
__entry->lun, __entry->rq_sector, __entry->wp_offset,
|
||||
__entry->good_bytes)
|
||||
);
|
||||
#endif /* _SD_TRACE_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH ../../drivers/scsi
|
||||
#include <trace/define_trace.h>
|
@ -20,6 +20,9 @@
|
||||
|
||||
#include "sd.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "sd_trace.h"
|
||||
|
||||
/**
|
||||
* sd_zbc_get_zone_wp_offset - Get zone write pointer offset.
|
||||
* @zone: Zone for which to return the write pointer offset.
|
||||
@ -450,6 +453,7 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba,
|
||||
break;
|
||||
}
|
||||
|
||||
trace_scsi_prepare_zone_append(cmd, *lba, wp_offset);
|
||||
*lba += wp_offset;
|
||||
}
|
||||
spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags);
|
||||
@ -558,6 +562,8 @@ static unsigned int sd_zbc_zone_wp_update(struct scsi_cmnd *cmd,
|
||||
|
||||
switch (op) {
|
||||
case REQ_OP_ZONE_APPEND:
|
||||
trace_scsi_zone_wp_update(cmd, rq->__sector,
|
||||
sdkp->zones_wp_offset[zno], good_bytes);
|
||||
rq->__sector += sdkp->zones_wp_offset[zno];
|
||||
fallthrough;
|
||||
case REQ_OP_WRITE_ZEROES:
|
||||
|
@ -1349,7 +1349,7 @@ sg_rq_end_io(struct request *rq, blk_status_t status)
|
||||
struct scsi_sense_hdr sshdr;
|
||||
|
||||
srp->header.status = 0xff & result;
|
||||
srp->header.masked_status = status_byte(result);
|
||||
srp->header.masked_status = sg_status_byte(result);
|
||||
srp->header.msg_status = COMMAND_COMPLETE;
|
||||
srp->header.host_status = host_byte(result);
|
||||
srp->header.driver_status = driver_byte(result);
|
||||
|
@ -121,6 +121,7 @@ enum scsi_disposition {
|
||||
* msg_byte (unused)
|
||||
* host_byte = set by low-level driver to indicate status.
|
||||
*/
|
||||
#define status_byte(result) (result & 0xff)
|
||||
#define host_byte(result) (((result) >> 16) & 0xff)
|
||||
|
||||
#define sense_class(sense) (((sense) >> 4) & 0x7)
|
||||
|
@ -159,7 +159,7 @@ struct compat_sg_io_hdr {
|
||||
#define TASK_ABORTED 0x20
|
||||
|
||||
/* Obsolete status_byte() declaration */
|
||||
#define status_byte(result) (((result) >> 1) & 0x7f)
|
||||
#define sg_status_byte(result) (((result) >> 1) & 0x7f)
|
||||
|
||||
typedef struct sg_scsi_id { /* used by SG_GET_SCSI_ID ioctl() */
|
||||
int host_no; /* as in "scsi<n>" where 'n' is one of 0, 1, 2 etc */
|
||||
|
@ -4,6 +4,23 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum pr_status {
|
||||
PR_STS_SUCCESS = 0x0,
|
||||
/*
|
||||
* The following error codes are based on SCSI, because the interface
|
||||
* was originally created for it and has existing users.
|
||||
*/
|
||||
/* Generic device failure. */
|
||||
PR_STS_IOERR = 0x2,
|
||||
PR_STS_RESERVATION_CONFLICT = 0x18,
|
||||
/* Temporary path failure that can be retried. */
|
||||
PR_STS_RETRY_PATH_FAILURE = 0xe0000,
|
||||
/* The request was failed due to a fast failure timer. */
|
||||
PR_STS_PATH_FAST_FAILED = 0xf0000,
|
||||
/* The path cannot be reached and has been marked as failed. */
|
||||
PR_STS_PATH_FAILED = 0x10000,
|
||||
};
|
||||
|
||||
enum pr_type {
|
||||
PR_WRITE_EXCLUSIVE = 1,
|
||||
PR_EXCLUSIVE_ACCESS = 2,
|
||||
|
Loading…
Reference in New Issue
Block a user