Commit 8395ae05 authored by Linus Torvalds's avatar Linus Torvalds

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
parents ff75ec43 68ad8318
......@@ -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);
}
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);
}
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,
......
/* 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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment