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, ...@@ -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); 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, static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
u64 key, u64 sa_key, u8 op) u64 key, u64 sa_key, u8 op)
{ {
struct nvme_command c = { }; struct nvme_command c = { };
u8 data[16] = { 0, }; u8 data[16] = { 0, };
int ret;
put_unaligned_le64(key, &data[0]); put_unaligned_le64(key, &data[0]);
put_unaligned_le64(sa_key, &data[8]); put_unaligned_le64(sa_key, &data[8]);
...@@ -2131,8 +2154,14 @@ static int nvme_pr_command(struct block_device *bdev, u32 cdw10, ...@@ -2131,8 +2154,14 @@ static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
if (IS_ENABLED(CONFIG_NVME_MULTIPATH) && if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
bdev->bd_disk->fops == &nvme_ns_head_ops) bdev->bd_disk->fops == &nvme_ns_head_ops)
return nvme_send_ns_head_pr_command(bdev, &c, data); ret = nvme_send_ns_head_pr_command(bdev, &c, data);
return nvme_send_ns_pr_command(bdev->bd_disk->private_data, &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, static int nvme_pr_register(struct block_device *bdev, u64 old,
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/rculist.h> #include <linux/list.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
......
...@@ -110,6 +110,7 @@ static void qla24xx_abort_iocb_timeout(void *data) ...@@ -110,6 +110,7 @@ static void qla24xx_abort_iocb_timeout(void *data)
struct qla_qpair *qpair = sp->qpair; struct qla_qpair *qpair = sp->qpair;
u32 handle; u32 handle;
unsigned long flags; unsigned long flags;
int sp_found = 0, cmdsp_found = 0;
if (sp->cmd_sp) if (sp->cmd_sp)
ql_dbg(ql_dbg_async, sp->vha, 0x507c, ql_dbg(ql_dbg_async, sp->vha, 0x507c,
...@@ -124,18 +125,21 @@ static void qla24xx_abort_iocb_timeout(void *data) ...@@ -124,18 +125,21 @@ static void qla24xx_abort_iocb_timeout(void *data)
spin_lock_irqsave(qpair->qp_lock_ptr, flags); spin_lock_irqsave(qpair->qp_lock_ptr, flags);
for (handle = 1; handle < qpair->req->num_outstanding_cmds; handle++) { for (handle = 1; handle < qpair->req->num_outstanding_cmds; handle++) {
if (sp->cmd_sp && (qpair->req->outstanding_cmds[handle] == if (sp->cmd_sp && (qpair->req->outstanding_cmds[handle] ==
sp->cmd_sp)) sp->cmd_sp)) {
qpair->req->outstanding_cmds[handle] = NULL; qpair->req->outstanding_cmds[handle] = NULL;
cmdsp_found = 1;
}
/* removing the abort */ /* removing the abort */
if (qpair->req->outstanding_cmds[handle] == sp) { if (qpair->req->outstanding_cmds[handle] == sp) {
qpair->req->outstanding_cmds[handle] = NULL; qpair->req->outstanding_cmds[handle] = NULL;
sp_found = 1;
break; break;
} }
} }
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 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 * This done function should take care of
* original command ref: INIT * original command ref: INIT
...@@ -143,8 +147,10 @@ static void qla24xx_abort_iocb_timeout(void *data) ...@@ -143,8 +147,10 @@ static void qla24xx_abort_iocb_timeout(void *data)
sp->cmd_sp->done(sp->cmd_sp, QLA_OS_TIMER_EXPIRED); sp->cmd_sp->done(sp->cmd_sp, QLA_OS_TIMER_EXPIRED);
} }
if (sp_found) {
abt->u.abt.comp_status = cpu_to_le16(CS_TIMEOUT); abt->u.abt.comp_status = cpu_to_le16(CS_TIMEOUT);
sp->done(sp, QLA_OS_TIMER_EXPIRED); sp->done(sp, QLA_OS_TIMER_EXPIRED);
}
} }
static void qla24xx_abort_sp_done(srb_t *sp, int res) 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, ...@@ -376,7 +376,7 @@ static int scsi_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
* fill in all the output members * fill in all the output members
*/ */
hdr->status = scmd->result & 0xff; 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->msg_status = COMMAND_COMPLETE;
hdr->host_status = host_byte(scmd->result); hdr->host_status = host_byte(scmd->result);
hdr->driver_status = 0; hdr->driver_status = 0;
......
...@@ -1709,6 +1709,36 @@ static char sd_pr_type(enum pr_type type) ...@@ -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, static int sd_pr_command(struct block_device *bdev, u8 sa,
u64 key, u64 sa_key, u8 type, u8 flags) u64 key, u64 sa_key, u8 type, u8 flags)
{ {
...@@ -1737,7 +1767,10 @@ static int sd_pr_command(struct block_device *bdev, u8 sa, ...@@ -1737,7 +1767,10 @@ static int sd_pr_command(struct block_device *bdev, u8 sa,
scsi_print_sense_hdr(sdev, NULL, &sshdr); scsi_print_sense_hdr(sdev, NULL, &sshdr);
} }
if (result <= 0)
return result; 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, 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 @@ ...@@ -20,6 +20,9 @@
#include "sd.h" #include "sd.h"
#define CREATE_TRACE_POINTS
#include "sd_trace.h"
/** /**
* sd_zbc_get_zone_wp_offset - Get zone write pointer offset. * sd_zbc_get_zone_wp_offset - Get zone write pointer offset.
* @zone: Zone for which to return the 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, ...@@ -450,6 +453,7 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba,
break; break;
} }
trace_scsi_prepare_zone_append(cmd, *lba, wp_offset);
*lba += wp_offset; *lba += wp_offset;
} }
spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags); 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, ...@@ -558,6 +562,8 @@ static unsigned int sd_zbc_zone_wp_update(struct scsi_cmnd *cmd,
switch (op) { switch (op) {
case REQ_OP_ZONE_APPEND: 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]; rq->__sector += sdkp->zones_wp_offset[zno];
fallthrough; fallthrough;
case REQ_OP_WRITE_ZEROES: case REQ_OP_WRITE_ZEROES:
......
...@@ -1349,7 +1349,7 @@ sg_rq_end_io(struct request *rq, blk_status_t status) ...@@ -1349,7 +1349,7 @@ sg_rq_end_io(struct request *rq, blk_status_t status)
struct scsi_sense_hdr sshdr; struct scsi_sense_hdr sshdr;
srp->header.status = 0xff & result; 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.msg_status = COMMAND_COMPLETE;
srp->header.host_status = host_byte(result); srp->header.host_status = host_byte(result);
srp->header.driver_status = driver_byte(result); srp->header.driver_status = driver_byte(result);
......
...@@ -121,6 +121,7 @@ enum scsi_disposition { ...@@ -121,6 +121,7 @@ enum scsi_disposition {
* msg_byte (unused) * msg_byte (unused)
* host_byte = set by low-level driver to indicate status. * host_byte = set by low-level driver to indicate status.
*/ */
#define status_byte(result) (result & 0xff)
#define host_byte(result) (((result) >> 16) & 0xff) #define host_byte(result) (((result) >> 16) & 0xff)
#define sense_class(sense) (((sense) >> 4) & 0x7) #define sense_class(sense) (((sense) >> 4) & 0x7)
......
...@@ -159,7 +159,7 @@ struct compat_sg_io_hdr { ...@@ -159,7 +159,7 @@ struct compat_sg_io_hdr {
#define TASK_ABORTED 0x20 #define TASK_ABORTED 0x20
/* Obsolete status_byte() declaration */ /* 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() */ 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 */ int host_no; /* as in "scsi<n>" where 'n' is one of 0, 1, 2 etc */
......
...@@ -4,6 +4,23 @@ ...@@ -4,6 +4,23 @@
#include <linux/types.h> #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 { enum pr_type {
PR_WRITE_EXCLUSIVE = 1, PR_WRITE_EXCLUSIVE = 1,
PR_EXCLUSIVE_ACCESS = 2, 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