diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.c | 2 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_main.c | 2 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfad.c | 22 | ||||
-rw-r--r-- | drivers/scsi/ch.c | 2 | ||||
-rw-r--r-- | drivers/scsi/csiostor/csio_init.c | 2 | ||||
-rw-r--r-- | drivers/scsi/hpsa.c | 6 | ||||
-rw-r--r-- | drivers/scsi/ipr.c | 3 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 3 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 6 | ||||
-rw-r--r-- | drivers/scsi/mac53c94.c | 10 | ||||
-rw-r--r-- | drivers/scsi/mesh.c | 14 | ||||
-rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 4 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mid.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 8 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 | ||||
-rw-r--r-- | drivers/scsi/scsi_error.c | 31 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 4 | ||||
-rw-r--r-- | drivers/scsi/sg.c | 15 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 27 | ||||
-rw-r--r-- | drivers/scsi/xen-scsifront.c | 219 |
22 files changed, 274 insertions, 114 deletions
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 80d97f3d2ed9..1028760b8a22 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -237,7 +237,7 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba, beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT | BEISCSI_LOG_EH | BEISCSI_LOG_CONFIG, - "BC_%d : Insufficent Buffer Error " + "BC_%d : Insufficient Buffer Error " "Resp_Len : %d Actual_Resp_Len : %d\n", mbx_resp_hdr->response_length, mbx_resp_hdr->actual_resp_len); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index a7cc61837818..923a2b5a2439 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -5734,9 +5734,9 @@ free_port: hba_free: if (phba->msix_enabled) pci_disable_msix(phba->pcidev); - iscsi_host_remove(phba->shost); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); + pci_set_drvdata(pcidev, NULL); disable_pci: pci_disable_device(pcidev); return ret; diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index e90a3742f09d..cc3b9d3d6d40 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -1079,22 +1079,18 @@ bfad_start_ops(struct bfad_s *bfad) { int bfad_worker(void *ptr) { - struct bfad_s *bfad; - unsigned long flags; - - bfad = (struct bfad_s *)ptr; - - while (!kthread_should_stop()) { + struct bfad_s *bfad = ptr; + unsigned long flags; - /* Send event BFAD_E_INIT_SUCCESS */ - bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); + if (kthread_should_stop()) + return 0; - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfad->bfad_tsk = NULL; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); + /* Send event BFAD_E_INIT_SUCCESS */ + bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); - break; - } + spin_lock_irqsave(&bfad->bfad_lock, flags); + bfad->bfad_tsk = NULL; + spin_unlock_irqrestore(&bfad->bfad_lock, flags); return 0; } diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 0045742fab7d..dad959fcf6d8 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -339,7 +339,7 @@ ch_readconfig(scsi_changer *ch) ch->firsts[CHET_DT], ch->counts[CHET_DT]); } else { - VPRINTK(KERN_INFO, "reading element address assigment page failed!\n"); + VPRINTK(KERN_INFO, "reading element address assignment page failed!\n"); } /* vendor specific element types */ diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c index d9631e15f7b5..dbe416ff46c2 100644 --- a/drivers/scsi/csiostor/csio_init.c +++ b/drivers/scsi/csiostor/csio_init.c @@ -1172,7 +1172,7 @@ static struct pci_error_handlers csio_err_handler = { * Macros needed to support the PCI Device ID Table ... */ #define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN \ - static struct pci_device_id csio_pci_tbl[] = { + static const struct pci_device_id csio_pci_tbl[] = { /* Define for FCoE uses PF6 */ #define CH_PCI_DEVICE_ID_FUNCTION 0x6 diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a1cfbd3dda47..8eab107b53fb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6632,14 +6632,12 @@ static void fail_all_outstanding_cmds(struct ctlr_info *h) static void set_lockup_detected_for_all_cpus(struct ctlr_info *h, u32 value) { - int i, cpu; + int cpu; - cpu = cpumask_first(cpu_online_mask); - for (i = 0; i < num_online_cpus(); i++) { + for_each_online_cpu(cpu) { u32 *lockup_detected; lockup_detected = per_cpu_ptr(h->lockup_detected, cpu); *lockup_detected = value; - cpu = cpumask_next(cpu, cpu_online_mask); } wmb(); /* be sure the per-cpu variables are out to memory */ } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 3128407b407d..882744852aac 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6901,7 +6901,8 @@ static struct ata_port_operations ipr_sata_ops = { }; static struct ata_port_info sata_port_info = { - .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA, + .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | + ATA_FLAG_SAS_HOST, .pio_mask = ATA_PIO4_ONLY, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA6, diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 932d9cc98d2f..9c706d8c1441 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -547,7 +547,8 @@ static struct ata_port_operations sas_sata_ops = { }; static struct ata_port_info sata_port_info = { - .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ, + .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ | + ATA_FLAG_SAS_HOST, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA6, diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 62b58d38ce2e..60de66252fa2 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -500,6 +500,7 @@ static void sas_revalidate_domain(struct work_struct *work) struct sas_discovery_event *ev = to_sas_discovery_event(work); struct asd_sas_port *port = ev->port; struct sas_ha_struct *ha = port->ha; + struct domain_device *ddev = port->port_dev; /* prevent revalidation from finding sata links in recovery */ mutex_lock(&ha->disco_mutex); @@ -514,8 +515,9 @@ static void sas_revalidate_domain(struct work_struct *work) SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, task_pid_nr(current)); - if (port->port_dev) - res = sas_ex_revalidate_domain(port->port_dev); + if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE || + ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE)) + res = sas_ex_revalidate_domain(ddev); SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", port->id, task_pid_nr(current), res); diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index e5cd8d8d4ce7..0adb2e015597 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -382,16 +382,16 @@ static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd) if (dma_len > 0xffff) panic("mac53c94: scatterlist element >= 64k"); total += dma_len; - st_le16(&dcmds->req_count, dma_len); - st_le16(&dcmds->command, dma_cmd); - st_le32(&dcmds->phy_addr, dma_addr); + dcmds->req_count = cpu_to_le16(dma_len); + dcmds->command = cpu_to_le16(dma_cmd); + dcmds->phy_addr = cpu_to_le32(dma_addr); dcmds->xfer_status = 0; ++dcmds; } dma_cmd += OUTPUT_LAST - OUTPUT_MORE; - st_le16(&dcmds[-1].command, dma_cmd); - st_le16(&dcmds->command, DBDMA_STOP); + dcmds[-1].command = cpu_to_le16(dma_cmd); + dcmds->command = cpu_to_le16(DBDMA_STOP); cmd->SCp.this_residual = total; } diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 57a95e2c3442..555367f00228 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1287,9 +1287,9 @@ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd) } if (dma_len > 0xffff) panic("mesh: scatterlist element >= 64k"); - st_le16(&dcmds->req_count, dma_len - off); - st_le16(&dcmds->command, dma_cmd); - st_le32(&dcmds->phy_addr, dma_addr + off); + dcmds->req_count = cpu_to_le16(dma_len - off); + dcmds->command = cpu_to_le16(dma_cmd); + dcmds->phy_addr = cpu_to_le32(dma_addr + off); dcmds->xfer_status = 0; ++dcmds; dtot += dma_len - off; @@ -1303,15 +1303,15 @@ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd) static char mesh_extra_buf[64]; dtot = sizeof(mesh_extra_buf); - st_le16(&dcmds->req_count, dtot); - st_le32(&dcmds->phy_addr, virt_to_phys(mesh_extra_buf)); + dcmds->req_count = cpu_to_le16(dtot); + dcmds->phy_addr = cpu_to_le32(virt_to_phys(mesh_extra_buf)); dcmds->xfer_status = 0; ++dcmds; } dma_cmd += OUTPUT_LAST - OUTPUT_MORE; - st_le16(&dcmds[-1].command, dma_cmd); + dcmds[-1].command = cpu_to_le16(dma_cmd); memset(dcmds, 0, sizeof(*dcmds)); - st_le16(&dcmds->command, DBDMA_STOP); + dcmds->command = cpu_to_le16(DBDMA_STOP); ms->dma_count = dtot; } diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 488c3929f19a..0cccd6033feb 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -186,7 +186,7 @@ static int _osd_get_print_system_info(struct osd_dev *od, if (unlikely(len > sizeof(odi->systemid))) { OSD_ERR("OSD Target error: OSD_SYSTEM_ID too long(%d). " - "device idetification might not work\n", len); + "device identification might not work\n", len); len = sizeof(odi->systemid); } odi->systemid_len = len; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 22ea00eb7750..285cb204f300 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5415,7 +5415,7 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) blob = qla2x00_request_firmware(vha); if (!blob) { ql_log(ql_log_info, vha, 0x0083, - "Fimware image unavailable.\n"); + "Firmware image unavailable.\n"); ql_log(ql_log_info, vha, 0x0084, "Firmware images can be retrieved from: "QLA_FW_URL ".\n"); return QLA_FUNCTION_FAILED; @@ -5518,7 +5518,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr) blob = qla2x00_request_firmware(vha); if (!blob) { ql_log(ql_log_warn, vha, 0x0090, - "Fimware image unavailable.\n"); + "Firmware image unavailable.\n"); ql_log(ql_log_warn, vha, 0x0091, "Firmware images can be retrieved from: " QLA_FW_URL ".\n"); diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 8f458efc125a..cc94192511cf 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -794,7 +794,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, rsp->msix = &ha->msix_entries[que_id + 1]; else ql_log(ql_log_warn, base_vha, 0x00e3, - "MSIX not enalbled.\n"); + "MSIX not enabled.\n"); ha->rsp_q_map[que_id] = rsp; rsp->rid = rid; diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 54cb2ac9339b..7d2b18f2675c 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1274,7 +1274,7 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) if (off == ADDR_ERROR) { ql_log(ql_log_fatal, vha, 0x0116, - "Unknow addr: 0x%08lx.\n", buf[i].addr); + "Unknown addr: 0x%08lx.\n", buf[i].addr); continue; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index e4851f863d20..7462dd70b150 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -446,11 +446,11 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) } ha->flags.cpu_affinity_enabled = 1; ql_dbg(ql_dbg_multiq, vha, 0xc007, - "CPU affinity mode enalbed, " + "CPU affinity mode enabled, " "no. of response queues:%d no. of request queues:%d.\n", ha->max_rsp_queues, ha->max_req_queues); ql_dbg(ql_dbg_init, vha, 0x00e9, - "CPU affinity mode enalbed, " + "CPU affinity mode enabled, " "no. of response queues:%d no. of request queues:%d.\n", ha->max_rsp_queues, ha->max_req_queues); } @@ -4102,7 +4102,7 @@ qla83xx_schedule_work(scsi_qla_host_t *base_vha, int work_code) break; default: ql_log(ql_log_warn, base_vha, 0xb05f, - "Unknow work-code=0x%x.\n", work_code); + "Unknown work-code=0x%x.\n", work_code); } return; @@ -4702,7 +4702,7 @@ qla83xx_idc_state_handler(scsi_qla_host_t *base_vha) break; default: ql_log(ql_log_warn, base_vha, 0xb071, - "Unknow Device State: %x.\n", dev_state); + "Unknown Device State: %x.\n", dev_state); qla83xx_idc_unlock(base_vha, 0); qla8xxx_dev_failed_handler(base_vha); rval = QLA_FUNCTION_FAILED; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 99f43b7fc9ab..ab4879e12ea7 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1596,7 +1596,7 @@ static int tcm_qla2xxx_check_initiator_node_acl( /* * Finally register the new FC Nexus with TCM */ - __transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess); + transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess); return 0; } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 4cdaffca17fc..c95a4e943fc6 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -26,6 +26,7 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/jiffies.h> +#include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -2586,3 +2587,33 @@ void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) } } EXPORT_SYMBOL(scsi_build_sense_buffer); + +/** + * scsi_set_sense_information - set the information field in a + * formatted sense data buffer + * @buf: Where to build sense data + * @info: 64-bit information value to be set + * + **/ +void scsi_set_sense_information(u8 *buf, u64 info) +{ + if ((buf[0] & 0x7f) == 0x72) { + u8 *ucp, len; + + len = buf[7]; + ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); + if (!ucp) { + buf[7] = len + 0xa; + ucp = buf + 8 + len; + } + ucp[0] = 0; + ucp[1] = 0xa; + ucp[2] = 0x80; /* Valid bit */ + ucp[3] = 0; + put_unaligned_be64(info, &ucp[4]); + } else if ((buf[0] & 0x7f) == 0x70) { + buf[0] |= 0x80; + put_unaligned_be64(info, &buf[3]); + } +} +EXPORT_SYMBOL(scsi_set_sense_information); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 54d7a6cbb98a..b1a263137a23 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1311,9 +1311,11 @@ scsi_prep_state_check(struct scsi_device *sdev, struct request *req) "rejecting I/O to dead device\n"); ret = BLKPREP_KILL; break; - case SDEV_QUIESCE: case SDEV_BLOCK: case SDEV_CREATED_BLOCK: + ret = BLKPREP_DEFER; + break; + case SDEV_QUIESCE: /* * If the devices is blocked we defer normal commands. */ diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 2270bd51f9c2..9d7b7db75e4b 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -33,7 +33,6 @@ static int sg_version_num = 30536; /* 2 digits for each component */ #include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> -#include <linux/aio.h> #include <linux/errno.h> #include <linux/mtio.h> #include <linux/ioctl.h> @@ -51,6 +50,7 @@ static int sg_version_num = 30536; /* 2 digits for each component */ #include <linux/mutex.h> #include <linux/atomic.h> #include <linux/ratelimit.h> +#include <linux/uio.h> #include "scsi.h" #include <scsi/scsi_dbg.h> @@ -1745,17 +1745,14 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) } if (iov_count) { - int size = sizeof(struct iovec) * iov_count; - struct iovec *iov; + struct iovec *iov = NULL; struct iov_iter i; - iov = memdup_user(hp->dxferp, size); - if (IS_ERR(iov)) - return PTR_ERR(iov); + res = import_iovec(rw, hp->dxferp, iov_count, 0, &iov, &i); + if (res < 0) + return res; - iov_iter_init(&i, rw, iov, iov_count, - min_t(size_t, hp->dxfer_len, - iov_length(iov, iov_count))); + iov_iter_truncate(&i, hp->dxfer_len); res = blk_rq_map_user_iov(q, rq, md, &i, GFP_ATOMIC); kfree(iov); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index dfd72af28f06..648a44675880 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4260,22 +4260,15 @@ static struct scsi_host_template ufshcd_driver_template = { static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, int ua) { - int ret = 0; - struct regulator *reg = vreg->reg; - const char *name = vreg->name; + int ret; - BUG_ON(!vreg); + if (!vreg) + return 0; - ret = regulator_set_optimum_mode(reg, ua); - if (ret >= 0) { - /* - * regulator_set_optimum_mode() returns new regulator - * mode upon success. - */ - ret = 0; - } else { - dev_err(dev, "%s: %s set optimum mode(ua=%d) failed, err=%d\n", - __func__, name, ua, ret); + ret = regulator_set_load(vreg->reg, ua); + if (ret < 0) { + dev_err(dev, "%s: %s set load (ua=%d) failed, err=%d\n", + __func__, vreg->name, ua, ret); } return ret; @@ -4284,18 +4277,12 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba, struct ufs_vreg *vreg) { - if (!vreg) - return 0; - return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA); } static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, struct ufs_vreg *vreg) { - if (!vreg) - return 0; - return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA); } diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c index 34199d206ba6..fad22caf0eff 100644 --- a/drivers/scsi/xen-scsifront.c +++ b/drivers/scsi/xen-scsifront.c @@ -63,6 +63,7 @@ #define VSCSIFRONT_OP_ADD_LUN 1 #define VSCSIFRONT_OP_DEL_LUN 2 +#define VSCSIFRONT_OP_READD_LUN 3 /* Tuning point. */ #define VSCSIIF_DEFAULT_CMD_PER_LUN 10 @@ -113,8 +114,13 @@ struct vscsifrnt_info { DECLARE_BITMAP(shadow_free_bitmap, VSCSIIF_MAX_REQS); struct vscsifrnt_shadow *shadow[VSCSIIF_MAX_REQS]; + /* Following items are protected by the host lock. */ wait_queue_head_t wq_sync; + wait_queue_head_t wq_pause; unsigned int wait_ring_available:1; + unsigned int waiting_pause:1; + unsigned int pause:1; + unsigned callers; char dev_state_path[64]; struct task_struct *curr; @@ -274,31 +280,31 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info, wake_up(&shadow->wq_reset); } -static int scsifront_cmd_done(struct vscsifrnt_info *info) +static void scsifront_do_response(struct vscsifrnt_info *info, + struct vscsiif_response *ring_rsp) +{ + if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS || + test_bit(ring_rsp->rqid, info->shadow_free_bitmap), + "illegal rqid %u returned by backend!\n", ring_rsp->rqid)) + return; + + if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB) + scsifront_cdb_cmd_done(info, ring_rsp); + else + scsifront_sync_cmd_done(info, ring_rsp); +} + +static int scsifront_ring_drain(struct vscsifrnt_info *info) { struct vscsiif_response *ring_rsp; RING_IDX i, rp; int more_to_do = 0; - unsigned long flags; - - spin_lock_irqsave(info->host->host_lock, flags); rp = info->ring.sring->rsp_prod; rmb(); /* ordering required respective to dom0 */ for (i = info->ring.rsp_cons; i != rp; i++) { - ring_rsp = RING_GET_RESPONSE(&info->ring, i); - - if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS || - test_bit(ring_rsp->rqid, info->shadow_free_bitmap), - "illegal rqid %u returned by backend!\n", - ring_rsp->rqid)) - continue; - - if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB) - scsifront_cdb_cmd_done(info, ring_rsp); - else - scsifront_sync_cmd_done(info, ring_rsp); + scsifront_do_response(info, ring_rsp); } info->ring.rsp_cons = i; @@ -308,6 +314,18 @@ static int scsifront_cmd_done(struct vscsifrnt_info *info) else info->ring.sring->rsp_event = i + 1; + return more_to_do; +} + +static int scsifront_cmd_done(struct vscsifrnt_info *info) +{ + int more_to_do; + unsigned long flags; + + spin_lock_irqsave(info->host->host_lock, flags); + + more_to_do = scsifront_ring_drain(info); + info->wait_ring_available = 0; spin_unlock_irqrestore(info->host->host_lock, flags); @@ -328,6 +346,24 @@ static irqreturn_t scsifront_irq_fn(int irq, void *dev_id) return IRQ_HANDLED; } +static void scsifront_finish_all(struct vscsifrnt_info *info) +{ + unsigned i; + struct vscsiif_response resp; + + scsifront_ring_drain(info); + + for (i = 0; i < VSCSIIF_MAX_REQS; i++) { + if (test_bit(i, info->shadow_free_bitmap)) + continue; + resp.rqid = i; + resp.sense_len = 0; + resp.rslt = DID_RESET << 16; + resp.residual_len = 0; + scsifront_do_response(info, &resp); + } +} + static int map_data_for_request(struct vscsifrnt_info *info, struct scsi_cmnd *sc, struct vscsiif_request *ring_req, @@ -475,6 +511,27 @@ static struct vscsiif_request *scsifront_command2ring( return ring_req; } +static int scsifront_enter(struct vscsifrnt_info *info) +{ + if (info->pause) + return 1; + info->callers++; + return 0; +} + +static void scsifront_return(struct vscsifrnt_info *info) +{ + info->callers--; + if (info->callers) + return; + + if (!info->waiting_pause) + return; + + info->waiting_pause = 0; + wake_up(&info->wq_pause); +} + static int scsifront_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) { @@ -486,6 +543,10 @@ static int scsifront_queuecommand(struct Scsi_Host *shost, uint16_t rqid; spin_lock_irqsave(shost->host_lock, flags); + if (scsifront_enter(info)) { + spin_unlock_irqrestore(shost->host_lock, flags); + return SCSI_MLQUEUE_HOST_BUSY; + } if (RING_FULL(&info->ring)) goto busy; @@ -505,6 +566,7 @@ static int scsifront_queuecommand(struct Scsi_Host *shost, if (err < 0) { pr_debug("%s: err %d\n", __func__, err); scsifront_put_rqid(info, rqid); + scsifront_return(info); spin_unlock_irqrestore(shost->host_lock, flags); if (err == -ENOMEM) return SCSI_MLQUEUE_HOST_BUSY; @@ -514,11 +576,13 @@ static int scsifront_queuecommand(struct Scsi_Host *shost, } scsifront_do_request(info); + scsifront_return(info); spin_unlock_irqrestore(shost->host_lock, flags); return 0; busy: + scsifront_return(info); spin_unlock_irqrestore(shost->host_lock, flags); pr_debug("%s: busy\n", __func__); return SCSI_MLQUEUE_HOST_BUSY; @@ -549,7 +613,7 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) if (ring_req) break; } - if (err) { + if (err || info->pause) { spin_unlock_irq(host->host_lock); kfree(shadow); return FAILED; @@ -561,6 +625,11 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) spin_lock_irq(host->host_lock); } + if (scsifront_enter(info)) { + spin_unlock_irq(host->host_lock); + return FAILED; + } + ring_req->act = act; ring_req->ref_rqid = s->rqid; @@ -587,6 +656,7 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) err = FAILED; } + scsifront_return(info); spin_unlock_irq(host->host_lock); return err; } @@ -644,6 +714,7 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info) { struct xenbus_device *dev = info->dev; struct vscsiif_sring *sring; + grant_ref_t gref; int err = -ENOMEM; /***** Frontend to Backend ring start *****/ @@ -656,14 +727,14 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info) SHARED_RING_INIT(sring); FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); - err = xenbus_grant_ring(dev, virt_to_mfn(sring)); + err = xenbus_grant_ring(dev, sring, 1, &gref); if (err < 0) { free_page((unsigned long)sring); xenbus_dev_fatal(dev, err, "fail to grant shared ring (Front to Back)"); return err; } - info->ring_ref = err; + info->ring_ref = gref; err = xenbus_alloc_evtchn(dev, &info->evtchn); if (err) { @@ -698,6 +769,13 @@ free_gnttab: return err; } +static void scsifront_free_ring(struct vscsifrnt_info *info) +{ + unbind_from_irqhandler(info->irq, info); + gnttab_end_foreign_access(info->ring_ref, 0, + (unsigned long)info->ring.sring); +} + static int scsifront_init_ring(struct vscsifrnt_info *info) { struct xenbus_device *dev = info->dev; @@ -744,9 +822,7 @@ again: fail: xenbus_transaction_end(xbt, 1); free_sring: - unbind_from_irqhandler(info->irq, info); - gnttab_end_foreign_access(info->ring_ref, 0, - (unsigned long)info->ring.sring); + scsifront_free_ring(info); return err; } @@ -779,6 +855,7 @@ static int scsifront_probe(struct xenbus_device *dev, } init_waitqueue_head(&info->wq_sync); + init_waitqueue_head(&info->wq_pause); spin_lock_init(&info->shadow_lock); snprintf(name, TASK_COMM_LEN, "vscsiif.%d", host->host_no); @@ -802,13 +879,60 @@ static int scsifront_probe(struct xenbus_device *dev, return 0; free_sring: - unbind_from_irqhandler(info->irq, info); - gnttab_end_foreign_access(info->ring_ref, 0, - (unsigned long)info->ring.sring); + scsifront_free_ring(info); scsi_host_put(host); return err; } +static int scsifront_resume(struct xenbus_device *dev) +{ + struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); + struct Scsi_Host *host = info->host; + int err; + + spin_lock_irq(host->host_lock); + + /* Finish all still pending commands. */ + scsifront_finish_all(info); + + spin_unlock_irq(host->host_lock); + + /* Reconnect to dom0. */ + scsifront_free_ring(info); + err = scsifront_init_ring(info); + if (err) { + dev_err(&dev->dev, "fail to resume %d\n", err); + scsi_host_put(host); + return err; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + + return 0; +} + +static int scsifront_suspend(struct xenbus_device *dev) +{ + struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); + struct Scsi_Host *host = info->host; + int err = 0; + + /* No new commands for the backend. */ + spin_lock_irq(host->host_lock); + info->pause = 1; + while (info->callers && !err) { + info->waiting_pause = 1; + info->wait_ring_available = 0; + spin_unlock_irq(host->host_lock); + wake_up(&info->wq_sync); + err = wait_event_interruptible(info->wq_pause, + !info->waiting_pause); + spin_lock_irq(host->host_lock); + } + spin_unlock_irq(host->host_lock); + return err; +} + static int scsifront_remove(struct xenbus_device *dev) { struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); @@ -823,10 +947,7 @@ static int scsifront_remove(struct xenbus_device *dev) } mutex_unlock(&scsifront_mutex); - gnttab_end_foreign_access(info->ring_ref, 0, - (unsigned long)info->ring.sring); - unbind_from_irqhandler(info->irq, info); - + scsifront_free_ring(info); scsi_host_put(info->host); return 0; @@ -919,6 +1040,12 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) scsi_device_put(sdev); } break; + case VSCSIFRONT_OP_READD_LUN: + if (device_state == XenbusStateConnected) + xenbus_printf(XBT_NIL, dev->nodename, + info->dev_state_path, + "%d", XenbusStateConnected); + break; default: break; } @@ -932,21 +1059,29 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) static void scsifront_read_backend_params(struct xenbus_device *dev, struct vscsifrnt_info *info) { - unsigned int sg_grant; + unsigned int sg_grant, nr_segs; int ret; struct Scsi_Host *host = info->host; ret = xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg-grant", "%u", &sg_grant); - if (ret == 1 && sg_grant) { - sg_grant = min_t(unsigned int, sg_grant, SG_ALL); - sg_grant = max_t(unsigned int, sg_grant, VSCSIIF_SG_TABLESIZE); - host->sg_tablesize = min_t(unsigned int, sg_grant, + if (ret != 1) + sg_grant = 0; + nr_segs = min_t(unsigned int, sg_grant, SG_ALL); + nr_segs = max_t(unsigned int, nr_segs, VSCSIIF_SG_TABLESIZE); + nr_segs = min_t(unsigned int, nr_segs, VSCSIIF_SG_TABLESIZE * PAGE_SIZE / sizeof(struct scsiif_request_segment)); - host->max_sectors = (host->sg_tablesize - 1) * PAGE_SIZE / 512; - } - dev_info(&dev->dev, "using up to %d SG entries\n", host->sg_tablesize); + + if (!info->pause && sg_grant) + dev_info(&dev->dev, "using up to %d SG entries\n", nr_segs); + else if (info->pause && nr_segs < host->sg_tablesize) + dev_warn(&dev->dev, + "SG entries decreased from %d to %u - device may not work properly anymore\n", + host->sg_tablesize, nr_segs); + + host->sg_tablesize = nr_segs; + host->max_sectors = (nr_segs - 1) * PAGE_SIZE / 512; } static void scsifront_backend_changed(struct xenbus_device *dev, @@ -965,6 +1100,14 @@ static void scsifront_backend_changed(struct xenbus_device *dev, case XenbusStateConnected: scsifront_read_backend_params(dev, info); + + if (info->pause) { + scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_READD_LUN); + xenbus_switch_state(dev, XenbusStateConnected); + info->pause = 0; + return; + } + if (xenbus_read_driver_state(dev->nodename) == XenbusStateInitialised) scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN); @@ -1002,6 +1145,8 @@ static struct xenbus_driver scsifront_driver = { .ids = scsifront_ids, .probe = scsifront_probe, .remove = scsifront_remove, + .resume = scsifront_resume, + .suspend = scsifront_suspend, .otherend_changed = scsifront_backend_changed, }; |