From 31c37a6f21d86e6bca095b71d603ed543ae070ad Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Mon, 24 Sep 2012 11:52:45 -0700 Subject: [SCSI] fcoe: Fix write errors on NPIV ports SCSI errors were generated while writing to LUNs connected via NPIV ports. Debugging this it was found that the FCoE packets transmitted via the NPIV ports were not tagged with correct user priority as negotiated with peer by DCB agent. This resulted in FCoE traffic going with priority zero(0) that did not have priority flow control (PFC) enabled for it. The initiator after transferring data to the target never saw any reply indicating the transfer was complete. This resulted in error recovery (ABTS) and SCSI command retries by the scsi-mid layer; eventually resulting in I/O errors. This patch fixes this issue by keeping the FCoE user priority information in the fcoe_interface instance that is common for both the physical port as well as NPIV ports connected to that physical port; instead of storing it in fcoe_port structure that has a per port instance. Signed-off-by: Neerav Parikh Acked-by: Yi Zou Acked-by: John Fastabend Tested-by: Marcus Dennis Signed-off-by: Robert Love Signed-off-by: James Bottomley --- include/scsi/libfcoe.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 22b07cc99808..8742d853a3b8 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -327,7 +327,6 @@ struct fcoe_percpu_s { * @lport: The associated local port * @fcoe_pending_queue: The pending Rx queue of skbs * @fcoe_pending_queue_active: Indicates if the pending queue is active - * @priority: Packet priority (DCB) * @max_queue_depth: Max queue depth of pending queue * @min_queue_depth: Min queue depth of pending queue * @timer: The queue timer @@ -343,7 +342,6 @@ struct fcoe_port { struct fc_lport *lport; struct sk_buff_head fcoe_pending_queue; u8 fcoe_pending_queue_active; - u8 priority; u32 max_queue_depth; u32 min_queue_depth; struct timer_list timer; -- cgit v1.2.3 From 3b64b1881143ce9e461c211cc81acc72d0cdc476 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 24 Sep 2012 11:52:50 -0700 Subject: [SCSI] libfc: fix lun reset failure bugs in fc_fcp_resp handling of FCP_RSP_INFO In LUN RESET testing involving NetApp targets, it is observed that LUN RESET is failing. The fc_fcp_resp() is not completing the completion for the LUN RESET task since fc_fcp_resp assumes that the FCP_RSP_INFO is 8 bytes with the 4 byte reserved field, where in case of NetApp targets the FCP_RSP to LUN RESET only has 4 bytes of FCP_RSP_INFO. This leads fc_fcp_resp to error out w/o completing the task completion, eventually causing LUN RESET to be escalated to host reset, which is not very nice. Per FCP-3 r04, clause 9.5.15 and Table 23, the FCP_RSP_INFO field can be either 4 bytes or 8 bytes, with the last 4 bytes as "Reserved (if any)". Therefore it is valid to have 4 bytes FCP_RSP_INFO like some of the NetApp targets behave. Fixing this by validating the FCP_RSP_INFO against both the two spec allowed length. Reported-by: Frank Zhang Signed-off-by: Yi Zou Tested-by: Ross Brattain Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_fcp.c | 3 ++- include/scsi/fc/fc_fcp.h | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 14243fa5f8e8..fcb9d0b20ee4 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -851,7 +851,8 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) fc_rp_info = (struct fcp_resp_rsp_info *)(rp_ex + 1); if (flags & FCP_RSP_LEN_VAL) { respl = ntohl(rp_ex->fr_rsp_len); - if (respl != sizeof(*fc_rp_info)) + if ((respl != FCP_RESP_RSP_INFO_LEN4) && + (respl != FCP_RESP_RSP_INFO_LEN8)) goto len_err; if (fsp->wait_for_comp) { /* Abuse cdb_status for rsp code */ diff --git a/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h index 0d7d67e96d43..9c8702942b61 100644 --- a/include/scsi/fc/fc_fcp.h +++ b/include/scsi/fc/fc_fcp.h @@ -127,6 +127,9 @@ struct fcp_txrdy { * * All response frames will always contain the fcp_resp template. Some * will also include the fcp_resp_len template. + * + * From Table 23, the FCP_RSP_INFO can either be 4 bytes or 8 bytes, both + * are valid length. */ struct fcp_resp { __u8 _fr_resvd[8]; /* reserved */ @@ -156,6 +159,9 @@ struct fcp_resp_rsp_info { __u8 _fr_resvd2[4]; /* reserved */ }; +#define FCP_RESP_RSP_INFO_LEN4 4 /* without reserved field */ +#define FCP_RESP_RSP_INFO_LEN8 8 /* with reserved field */ + struct fcp_resp_with_ext { struct fcp_resp resp; struct fcp_resp_ext ext; -- cgit v1.2.3 From 865b58c05b841964f48f574c2027311bd04db8a1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 2 Oct 2012 17:25:48 +0200 Subject: [SCSI] virtio-scsi: support online resizing of disks Support the LUN parameter change event. Currently, the host fires this event when the capacity of a disk is changed from the virtual machine monitor. The resize then appears in the kernel log like this: sd 0:0:0:0: [sda] 46137344 512-byte logical blocks: (23.6 GB/22.0 GIb) sda: detected capacity change from 22548578304 to 23622320128 Signed-off-by: Paolo Bonzini Signed-off-by: James Bottomley --- drivers/scsi/virtio_scsi.c | 31 ++++++++++++++++++++++++++++++- include/linux/virtio_scsi.h | 2 ++ 2 files changed, 32 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index a7cf726bc747..595af1ae4421 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -279,6 +279,31 @@ static void virtscsi_handle_transport_reset(struct virtio_scsi *vscsi, } } +static void virtscsi_handle_param_change(struct virtio_scsi *vscsi, + struct virtio_scsi_event *event) +{ + struct scsi_device *sdev; + struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); + unsigned int target = event->lun[1]; + unsigned int lun = (event->lun[2] << 8) | event->lun[3]; + u8 asc = event->reason & 255; + u8 ascq = event->reason >> 8; + + sdev = scsi_device_lookup(shost, 0, target, lun); + if (!sdev) { + pr_err("SCSI device %d 0 %d %d not found\n", + shost->host_no, target, lun); + return; + } + + /* Handle "Parameters changed", "Mode parameters changed", and + "Capacity data has changed". */ + if (asc == 0x2a && (ascq == 0x00 || ascq == 0x01 || ascq == 0x09)) + scsi_rescan_device(&sdev->sdev_gendev); + + scsi_device_put(sdev); +} + static void virtscsi_handle_event(struct work_struct *work) { struct virtio_scsi_event_node *event_node = @@ -297,6 +322,9 @@ static void virtscsi_handle_event(struct work_struct *work) case VIRTIO_SCSI_T_TRANSPORT_RESET: virtscsi_handle_transport_reset(vscsi, event); break; + case VIRTIO_SCSI_T_PARAM_CHANGE: + virtscsi_handle_param_change(vscsi, event); + break; default: pr_err("Unsupport virtio scsi event %x\n", event->event); } @@ -737,7 +765,8 @@ static struct virtio_device_id id_table[] = { }; static unsigned int features[] = { - VIRTIO_SCSI_F_HOTPLUG + VIRTIO_SCSI_F_HOTPLUG, + VIRTIO_SCSI_F_CHANGE, }; static struct virtio_driver virtio_scsi_driver = { diff --git a/include/linux/virtio_scsi.h b/include/linux/virtio_scsi.h index dc8d305b0e05..d6b4440387b7 100644 --- a/include/linux/virtio_scsi.h +++ b/include/linux/virtio_scsi.h @@ -72,6 +72,7 @@ struct virtio_scsi_config { /* Feature Bits */ #define VIRTIO_SCSI_F_INOUT 0 #define VIRTIO_SCSI_F_HOTPLUG 1 +#define VIRTIO_SCSI_F_CHANGE 2 /* Response codes */ #define VIRTIO_SCSI_S_OK 0 @@ -108,6 +109,7 @@ struct virtio_scsi_config { #define VIRTIO_SCSI_T_NO_EVENT 0 #define VIRTIO_SCSI_T_TRANSPORT_RESET 1 #define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 +#define VIRTIO_SCSI_T_PARAM_CHANGE 3 /* Reasons of transport reset event */ #define VIRTIO_SCSI_EVT_RESET_HARD 0 -- cgit v1.2.3 From 329a402cb052b233bc92aa34c4caf2f7dfb2d76e Mon Sep 17 00:00:00 2001 From: Li Zhong Date: Sat, 29 Sep 2012 12:23:37 +0800 Subject: [SCSI] Shorten the path length of scsi_cmd_to_driver() This patch tries to shorten the path length of scsi_cmd_to_driver(). As only REQ_TYPE_BLOCK_PC commands can be submitted without a driver, so we could avoid the related NULL checking, as long as we make sure we don't use it for REQ_TYPE_BLOCK_PC type commands. Plus, this fixes a bug where you get different behaviors from REQ_TYPE_BLOCK_PC commands when a driver is and isn't attached. Signed-off-by: Li Zhong Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 8 +++++--- include/scsi/scsi_cmnd.h | 12 ++---------- 2 files changed, 7 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index de2337f255a7..c1b05a83d403 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -789,7 +789,6 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, int cmnd_size, int timeout, unsigned sense_bytes) { struct scsi_device *sdev = scmd->device; - struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); struct Scsi_Host *shost = sdev->host; DECLARE_COMPLETION_ONSTACK(done); unsigned long timeleft; @@ -845,8 +844,11 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, scsi_eh_restore_cmnd(scmd, &ses); - if (sdrv && sdrv->eh_action) - rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn); + if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { + struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); + if (sdrv->eh_action) + rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn); + } return rtn; } diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index ac06cc595890..de5f5d8f1f8a 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -132,18 +132,10 @@ struct scsi_cmnd { unsigned char tag; /* SCSI-II queued command tag */ }; +/* make sure not to use it with REQ_TYPE_BLOCK_PC commands */ static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) { - struct scsi_driver **sdp; - - if (!cmd->request->rq_disk) - return NULL; - - sdp = (struct scsi_driver **)cmd->request->rq_disk->private_data; - if (!sdp) - return NULL; - - return *sdp; + return *(struct scsi_driver **)cmd->request->rq_disk->private_data; } extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); -- cgit v1.2.3