diff options
Diffstat (limited to 'drivers')
187 files changed, 12247 insertions, 8007 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 436e17f1d0e5..67f65dcb15a6 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -1528,12 +1528,12 @@ isert_check_pi_status(struct se_cmd *se_cmd, struct ib_mr *sig_mr) } sec_offset_err = mr_status.sig_err.sig_err_offset; do_div(sec_offset_err, block_size); - se_cmd->bad_sector = sec_offset_err + se_cmd->t_task_lba; + se_cmd->sense_info = sec_offset_err + se_cmd->t_task_lba; isert_err("PI error found type %d at sector 0x%llx " "expected 0x%x vs actual 0x%x\n", mr_status.sig_err.err_type, - (unsigned long long)se_cmd->bad_sector, + (unsigned long long)se_cmd->sense_info, mr_status.sig_err.expected, mr_status.sig_err.actual); ret = 1; @@ -2471,7 +2471,7 @@ isert_wait4cmds(struct iscsi_conn *conn) isert_info("iscsi_conn %p\n", conn); if (conn->sess) { - target_sess_cmd_list_set_waiting(conn->sess->se_sess); + target_stop_session(conn->sess->se_sess); target_wait_for_sess_cmds(conn->sess->se_sess); } } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 53a8becac827..a17c56cd8312 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2085,7 +2085,7 @@ static void srpt_release_channel_work(struct work_struct *w) se_sess = ch->sess; BUG_ON(!se_sess); - target_sess_cmd_list_set_waiting(se_sess); + target_stop_session(se_sess); target_wait_for_sess_cmds(se_sess); target_remove_session(se_sess); diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 9903e9660a38..549797d0301d 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -57,7 +57,7 @@ #include <linux/kdev_t.h> #include <linux/blkdev.h> #include <linux/delay.h> -#include <linux/interrupt.h> /* needed for in_interrupt() proto */ +#include <linux/interrupt.h> #include <linux/dma-mapping.h> #include <linux/kthread.h> #include <scsi/scsi_host.h> @@ -473,7 +473,6 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) mpt_free_msg_frame(ioc, mf); mb(); return; - break; } mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); break; @@ -6336,7 +6335,6 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) * Page header is updated. * * Returns 0 for success - * -EPERM if not allowed due to ISR context * -EAGAIN if no msg frames currently available * -EFAULT for non-successful reply or no reply (timeout) */ @@ -6354,19 +6352,10 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) u8 page_type = 0, extend_page; unsigned long timeleft; unsigned long flags; - int in_isr; u8 issue_hard_reset = 0; u8 retry_count = 0; - /* Prevent calling wait_event() (below), if caller happens - * to be in ISR context, because that is fatal! - */ - in_isr = in_interrupt(); - if (in_isr) { - dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", - ioc->name)); - return -EPERM; - } + might_sleep(); /* don't send a config page during diag reset */ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index f92b0433f599..0484e9c15c09 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -50,7 +50,7 @@ #include <linux/kdev_t.h> #include <linux/blkdev.h> #include <linux/delay.h> /* for mdelay */ -#include <linux/interrupt.h> /* needed for in_interrupt() proto */ +#include <linux/interrupt.h> #include <linux/reboot.h> /* notifier code */ #include <linux/workqueue.h> #include <linux/sort.h> diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 18b91ea1a353..5eb0b3361e4e 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -289,6 +289,7 @@ mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, spin_lock_irqsave(&ioc->fw_event_lock, flags); list_add_tail(&fw_event->list, &ioc->fw_event_list); + fw_event->users = 1; INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)" "on cpuid %d\n", ioc->name, __func__, @@ -314,6 +315,15 @@ mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } +static void __mptsas_free_fw_event(MPT_ADAPTER *ioc, + struct fw_event_work *fw_event) +{ + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n", + ioc->name, __func__, fw_event)); + list_del(&fw_event->list); + kfree(fw_event); +} + /* free memory associated to a sas firmware event */ static void mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) @@ -321,10 +331,9 @@ mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) unsigned long flags; spin_lock_irqsave(&ioc->fw_event_lock, flags); - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n", - ioc->name, __func__, fw_event)); - list_del(&fw_event->list); - kfree(fw_event); + fw_event->users--; + if (!fw_event->users) + __mptsas_free_fw_event(ioc, fw_event); spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } @@ -333,9 +342,10 @@ mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) static void mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) { - struct fw_event_work *fw_event, *next; + struct fw_event_work *fw_event; struct mptsas_target_reset_event *target_reset_list, *n; MPT_SCSI_HOST *hd = shost_priv(ioc->sh); + unsigned long flags; /* flush the target_reset_list */ if (!list_empty(&hd->target_reset_list)) { @@ -350,14 +360,29 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) } } - if (list_empty(&ioc->fw_event_list) || - !ioc->fw_event_q || in_interrupt()) + if (list_empty(&ioc->fw_event_list) || !ioc->fw_event_q) return; - list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { - if (cancel_delayed_work(&fw_event->work)) - mptsas_free_fw_event(ioc, fw_event); + spin_lock_irqsave(&ioc->fw_event_lock, flags); + + while (!list_empty(&ioc->fw_event_list)) { + bool canceled = false; + + fw_event = list_first_entry(&ioc->fw_event_list, + struct fw_event_work, list); + fw_event->users++; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + if (cancel_delayed_work_sync(&fw_event->work)) + canceled = true; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + if (canceled) + fw_event->users--; + fw_event->users--; + WARN_ON_ONCE(fw_event->users); + __mptsas_free_fw_event(ioc, fw_event); } + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h index e35b13891fe4..71abf3477495 100644 --- a/drivers/message/fusion/mptsas.h +++ b/drivers/message/fusion/mptsas.h @@ -107,6 +107,7 @@ struct mptsas_hotplug_event { struct fw_event_work { struct list_head list; struct delayed_work work; + int users; MPT_ADAPTER *ioc; u32 event; u8 retries; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index e7f0d4ae0f96..ce2e5b21978e 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -52,7 +52,7 @@ #include <linux/kdev_t.h> #include <linux/blkdev.h> #include <linux/delay.h> /* for mdelay */ -#include <linux/interrupt.h> /* needed for in_interrupt() proto */ +#include <linux/interrupt.h> #include <linux/reboot.h> /* notifier code */ #include <linux/workqueue.h> diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index eabc4de5816c..af0ce5611e4a 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -52,7 +52,7 @@ #include <linux/kdev_t.h> #include <linux/blkdev.h> #include <linux/delay.h> /* for mdelay */ -#include <linux/interrupt.h> /* needed for in_interrupt() proto */ +#include <linux/interrupt.h> #include <linux/reboot.h> /* notifier code */ #include <linux/workqueue.h> #include <linux/raid_class.h> diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 18b713a616de..768873dd55b8 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -292,6 +292,14 @@ static void _zfcp_status_read_scheduler(struct work_struct *work) stat_work)); } +static void zfcp_version_change_lost_work(struct work_struct *work) +{ + struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter, + version_change_lost_work); + + zfcp_fsf_exchange_config_data_sync(adapter->qdio, NULL); +} + static void zfcp_print_sl(struct seq_file *m, struct service_level *sl) { struct zfcp_adapter *adapter = @@ -353,6 +361,8 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); INIT_DELAYED_WORK(&adapter->scan_work, zfcp_fc_scan_ports); INIT_WORK(&adapter->ns_up_work, zfcp_fc_sym_name_update); + INIT_WORK(&adapter->version_change_lost_work, + zfcp_version_change_lost_work); adapter->next_port_scan = jiffies; @@ -429,6 +439,7 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter) cancel_delayed_work_sync(&adapter->scan_work); cancel_work_sync(&adapter->stat_work); cancel_work_sync(&adapter->ns_up_work); + cancel_work_sync(&adapter->version_change_lost_work); zfcp_destroy_adapter_work_queue(adapter); zfcp_fc_wka_ports_force_offline(adapter->gs); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 5069b555c6c1..26c89c232ef2 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -200,6 +200,7 @@ struct zfcp_adapter { struct zfcp_fc_events events; unsigned long next_port_scan; struct zfcp_diag_adapter *diagnostics; + struct work_struct version_change_lost_work; }; struct zfcp_port { diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index fdac6350c579..58879213f225 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -20,8 +20,6 @@ extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, u32); -extern void zfcp_sg_free_table(struct scatterlist *, int); -extern int zfcp_sg_setup_table(struct scatterlist *, int); extern void zfcp_adapter_release(struct kref *); extern void zfcp_adapter_unregister(struct zfcp_adapter *); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 37d450f46952..485028324eae 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -242,6 +242,19 @@ static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) } } +static void +zfcp_fsf_status_read_version_change(struct zfcp_adapter *adapter, + struct fsf_status_read_buffer *sr_buf) +{ + if (sr_buf->status_subtype == FSF_STATUS_READ_SUB_LIC_CHANGE) { + u32 version = sr_buf->payload.version_change.current_version; + + WRITE_ONCE(adapter->fsf_lic_version, version); + snprintf(fc_host_firmware_version(adapter->scsi_host), + FC_VERSION_STRING_SIZE, "%#08x", version); + } +} + static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; @@ -296,10 +309,16 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) case FSF_STATUS_READ_NOTIFICATION_LOST: if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) zfcp_fc_conditional_port_scan(adapter); + if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_VERSION_CHANGE) + queue_work(adapter->work_queue, + &adapter->version_change_lost_work); break; case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: adapter->adapter_features = sr_buf->payload.word[0]; break; + case FSF_STATUS_READ_VERSION_CHANGE: + zfcp_fsf_status_read_version_change(adapter, sr_buf); + break; } mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data); diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 09d73d0061ef..5e6b601af980 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -134,6 +134,7 @@ #define FSF_STATUS_READ_LINK_UP 0x00000006 #define FSF_STATUS_READ_NOTIFICATION_LOST 0x00000009 #define FSF_STATUS_READ_FEATURE_UPDATE_ALERT 0x0000000C +#define FSF_STATUS_READ_VERSION_CHANGE 0x0000000D /* status subtypes for link down */ #define FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK 0x00000000 @@ -142,6 +143,10 @@ /* status subtypes for unsolicited status notification lost */ #define FSF_STATUS_READ_SUB_INCOMING_ELS 0x00000001 +#define FSF_STATUS_READ_SUB_VERSION_CHANGE 0x00000100 + +/* status subtypes for version change */ +#define FSF_STATUS_READ_SUB_LIC_CHANGE 0x00000001 /* topologie that is detected by the adapter */ #define FSF_TOPO_P2P 0x00000001 @@ -226,6 +231,11 @@ struct fsf_link_down_info { u8 vendor_specific_code; } __attribute__ ((packed)); +struct fsf_version_change { + u32 current_version; + u32 previous_version; +} __packed; + struct fsf_status_read_buffer { u32 status_type; u32 status_subtype; @@ -242,6 +252,7 @@ struct fsf_status_read_buffer { u32 word[FSF_STATUS_READ_PAYLOAD_SIZE/sizeof(u32)]; struct fsf_link_down_info link_down_info; struct fsf_bit_error_payload bit_error; + struct fsf_version_change version_change; } payload; } __attribute__ ((packed)); diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index a8a514074084..23ab16d65f2a 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -10,6 +10,7 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/lockdep.h> #include <linux/slab.h> #include <linux/module.h> #include "zfcp_ext.h" @@ -131,6 +132,33 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2"); } +static void zfcp_qdio_irq_tasklet(struct tasklet_struct *tasklet) +{ + struct zfcp_qdio *qdio = from_tasklet(qdio, tasklet, irq_tasklet); + struct ccw_device *cdev = qdio->adapter->ccw_device; + unsigned int start, error; + int completed; + + /* Check the Response Queue, and kick off the Request Queue tasklet: */ + completed = qdio_get_next_buffers(cdev, 0, &start, &error); + if (completed < 0) + return; + if (completed > 0) + zfcp_qdio_int_resp(cdev, error, 0, start, completed, + (unsigned long) qdio); + + if (qdio_start_irq(cdev)) + /* More work pending: */ + tasklet_schedule(&qdio->irq_tasklet); +} + +static void zfcp_qdio_poll(struct ccw_device *cdev, unsigned long data) +{ + struct zfcp_qdio *qdio = (struct zfcp_qdio *) data; + + tasklet_schedule(&qdio->irq_tasklet); +} + static struct qdio_buffer_element * zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) { @@ -256,6 +284,13 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) int retval; u8 sbal_number = q_req->sbal_number; + /* + * This should actually be a spin_lock_bh(stat_lock), to protect against + * zfcp_qdio_int_req() in tasklet context. + * But we can't do so (and are safe), as we always get called with IRQs + * disabled by spin_lock_irq[save](req_q_lock). + */ + lockdep_assert_irqs_disabled(); spin_lock(&qdio->stat_lock); zfcp_qdio_account(qdio); spin_unlock(&qdio->stat_lock); @@ -332,6 +367,8 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) wake_up(&qdio->req_q_wq); + tasklet_disable(&qdio->irq_tasklet); + qdio_stop_irq(adapter->ccw_device); qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); /* cleanup used outbound sbals */ @@ -387,6 +424,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) init_data.no_output_qs = 1; init_data.input_handler = zfcp_qdio_int_resp; init_data.output_handler = zfcp_qdio_int_req; + init_data.irq_poll = zfcp_qdio_poll; init_data.int_parm = (unsigned long) qdio; init_data.input_sbal_addr_array = input_sbals; init_data.output_sbal_addr_array = output_sbals; @@ -433,6 +471,11 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); atomic_or(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); + /* Enable processing for QDIO interrupts: */ + tasklet_enable(&qdio->irq_tasklet); + /* This results in a qdio_start_irq(): */ + tasklet_schedule(&qdio->irq_tasklet); + zfcp_qdio_shost_update(adapter, qdio); return 0; @@ -450,6 +493,8 @@ void zfcp_qdio_destroy(struct zfcp_qdio *qdio) if (!qdio) return; + tasklet_kill(&qdio->irq_tasklet); + if (qdio->adapter->ccw_device) qdio_free(qdio->adapter->ccw_device); @@ -475,6 +520,8 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter) spin_lock_init(&qdio->req_q_lock); spin_lock_init(&qdio->stat_lock); + tasklet_setup(&qdio->irq_tasklet, zfcp_qdio_irq_tasklet); + tasklet_disable(&qdio->irq_tasklet); adapter->qdio = qdio; return 0; diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h index 6b43d6b254be..9c1f310db155 100644 --- a/drivers/s390/scsi/zfcp_qdio.h +++ b/drivers/s390/scsi/zfcp_qdio.h @@ -10,6 +10,7 @@ #ifndef ZFCP_QDIO_H #define ZFCP_QDIO_H +#include <linux/interrupt.h> #include <asm/qdio.h> #define ZFCP_QDIO_SBALE_LEN PAGE_SIZE @@ -44,6 +45,7 @@ struct zfcp_qdio { u64 req_q_util; atomic_t req_q_full; wait_queue_head_t req_q_wq; + struct tasklet_struct irq_tasklet; struct zfcp_adapter *adapter; u16 max_sbale_per_sbal; u16 max_sbale_per_req; diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 3337b1e80412..b4718a1b2bd6 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -2191,10 +2191,10 @@ static void twa_remove(struct pci_dev *pdev) twa_device_extension_count--; } /* End twa_remove() */ -#ifdef CONFIG_PM /* This function is called on PCI suspend */ -static int twa_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused twa_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct Scsi_Host *host = pci_get_drvdata(pdev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; @@ -2214,32 +2214,19 @@ static int twa_suspend(struct pci_dev *pdev, pm_message_t state) } TW_CLEAR_ALL_INTERRUPTS(tw_dev); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } /* End twa_suspend() */ /* This function is called on PCI resume */ -static int twa_resume(struct pci_dev *pdev) +static int __maybe_unused twa_resume(struct device *dev) { int retval = 0; + struct pci_dev *pdev = to_pci_dev(dev); struct Scsi_Host *host = pci_get_drvdata(pdev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; printk(KERN_WARNING "3w-9xxx: Resuming host %d.\n", tw_dev->host->host_no); - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - retval = pci_enable_device(pdev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x39, "Enable device failed during resume"); - return retval; - } - - pci_set_master(pdev); pci_try_set_mwi(pdev); retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); @@ -2277,11 +2264,9 @@ static int twa_resume(struct pci_dev *pdev) out_disable_device: scsi_remove_host(host); - pci_disable_device(pdev); return retval; } /* End twa_resume() */ -#endif /* PCI Devices supported by this driver */ static struct pci_device_id twa_pci_tbl[] = { @@ -2297,16 +2282,15 @@ static struct pci_device_id twa_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, twa_pci_tbl); +static SIMPLE_DEV_PM_OPS(twa_pm_ops, twa_suspend, twa_resume); + /* pci_driver initializer */ static struct pci_driver twa_driver = { .name = "3w-9xxx", .id_table = twa_pci_tbl, .probe = twa_probe, .remove = twa_remove, -#ifdef CONFIG_PM - .suspend = twa_suspend, - .resume = twa_resume, -#endif + .driver.pm = &twa_pm_ops, .shutdown = twa_shutdown }; diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index dda6fa857709..b8f1848ecef2 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1756,11 +1756,10 @@ static void twl_remove(struct pci_dev *pdev) twl_device_extension_count--; } /* End twl_remove() */ -#ifdef CONFIG_PM /* This function is called on PCI suspend */ -static int twl_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused twl_suspend(struct device *dev) { - struct Scsi_Host *host = pci_get_drvdata(pdev); + struct Scsi_Host *host = dev_get_drvdata(dev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; printk(KERN_WARNING "3w-sas: Suspending host %d.\n", tw_dev->host->host_no); @@ -1779,32 +1778,18 @@ static int twl_suspend(struct pci_dev *pdev, pm_message_t state) /* Clear doorbell interrupt */ TWL_CLEAR_DB_INTERRUPT(tw_dev); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } /* End twl_suspend() */ /* This function is called on PCI resume */ -static int twl_resume(struct pci_dev *pdev) +static int __maybe_unused twl_resume(struct device *dev) { int retval = 0; + struct pci_dev *pdev = to_pci_dev(dev); struct Scsi_Host *host = pci_get_drvdata(pdev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; printk(KERN_WARNING "3w-sas: Resuming host %d.\n", tw_dev->host->host_no); - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - retval = pci_enable_device(pdev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x24, "Enable device failed during resume"); - return retval; - } - - pci_set_master(pdev); pci_try_set_mwi(pdev); retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); @@ -1842,11 +1827,9 @@ static int twl_resume(struct pci_dev *pdev) out_disable_device: scsi_remove_host(host); - pci_disable_device(pdev); return retval; } /* End twl_resume() */ -#endif /* PCI Devices supported by this driver */ static struct pci_device_id twl_pci_tbl[] = { @@ -1855,16 +1838,15 @@ static struct pci_device_id twl_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, twl_pci_tbl); +static SIMPLE_DEV_PM_OPS(twl_pm_ops, twl_suspend, twl_resume); + /* pci_driver initializer */ static struct pci_driver twl_driver = { .name = "3w-sas", .id_table = twl_pci_tbl, .probe = twl_probe, .remove = twl_remove, -#ifdef CONFIG_PM - .suspend = twl_suspend, - .resume = twl_resume, -#endif + .driver.pm = &twl_pm_ops, .shutdown = twl_shutdown }; diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index d654a6cc4162..2ddbcaa667d1 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -132,7 +132,7 @@ static unsigned int disconnect_mask = ~0; module_param(disconnect_mask, int, 0444); -static int do_abort(struct Scsi_Host *); +static int do_abort(struct Scsi_Host *, unsigned int); static void do_reset(struct Scsi_Host *); static void bus_reset_cleanup(struct Scsi_Host *); @@ -197,7 +197,7 @@ static inline void set_resid_from_SCp(struct scsi_cmnd *cmd) * @reg2: Second 5380 register to poll * @bit2: Second bitmask to check * @val2: Second expected value - * @wait: Time-out in jiffies + * @wait: Time-out in jiffies, 0 if sleeping is not allowed * * Polls the chip in a reasonably efficient manner waiting for an * event to occur. After a short quick poll we begin to yield the CPU @@ -223,7 +223,7 @@ static int NCR5380_poll_politely2(struct NCR5380_hostdata *hostdata, cpu_relax(); } while (n--); - if (irqs_disabled() || in_interrupt()) + if (!wait) return -ETIMEDOUT; /* Repeatedly sleep for 1 ms until deadline */ @@ -486,7 +486,7 @@ static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance) break; case 2: shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n"); - do_abort(instance); + do_abort(instance, 1); break; case 4: shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n"); @@ -580,11 +580,14 @@ static int NCR5380_queue_command(struct Scsi_Host *instance, cmd->result = 0; - if (!NCR5380_acquire_dma_irq(instance)) - return SCSI_MLQUEUE_HOST_BUSY; - spin_lock_irqsave(&hostdata->lock, flags); + if (!NCR5380_acquire_dma_irq(instance)) { + spin_unlock_irqrestore(&hostdata->lock, flags); + + return SCSI_MLQUEUE_HOST_BUSY; + } + /* * Insert the cmd into the issue queue. Note that REQUEST SENSE * commands are added to the head of the queue since any command will @@ -722,7 +725,6 @@ static void NCR5380_main(struct work_struct *work) if (!NCR5380_select(instance, cmd)) { dsprintk(NDEBUG_MAIN, instance, "main: select complete\n"); - maybe_release_dma_irq(instance); } else { dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance, "main: select failed, returning %p to queue\n", cmd); @@ -734,8 +736,10 @@ static void NCR5380_main(struct work_struct *work) NCR5380_information_transfer(instance); done = 0; } - if (!hostdata->connected) + if (!hostdata->connected) { NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + maybe_release_dma_irq(instance); + } spin_unlock_irq(&hostdata->lock); if (!done) cond_resched(); @@ -818,7 +822,7 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance) if (toPIO > 0) { dsprintk(NDEBUG_DMA, instance, "Doing %d byte PIO to 0x%p\n", cnt, *data); - NCR5380_transfer_pio(instance, &p, &cnt, data); + NCR5380_transfer_pio(instance, &p, &cnt, data, 0); *count -= toPIO - cnt; } } @@ -1185,7 +1189,7 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) goto out; } if (!hostdata->selecting) { - do_abort(instance); + do_abort(instance, 0); return false; } @@ -1196,7 +1200,7 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) len = 1; data = tmp; phase = PHASE_MSGOUT; - NCR5380_transfer_pio(instance, &phase, &len, &data); + NCR5380_transfer_pio(instance, &phase, &len, &data, 0); if (len) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); cmd->result = DID_ERROR << 16; @@ -1234,7 +1238,8 @@ out: * * Inputs : instance - instance of driver, *phase - pointer to * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer. + * bytes to transfer, **data - pointer to data pointer, + * can_sleep - 1 or 0 when sleeping is permitted or not, respectively. * * Returns : -1 when different phase is entered without transferring * maximum number of bytes, 0 if all bytes are transferred or exit @@ -1253,7 +1258,7 @@ out: static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, - unsigned char **data) + unsigned char **data, unsigned int can_sleep) { struct NCR5380_hostdata *hostdata = shost_priv(instance); unsigned char p = *phase, tmp; @@ -1274,7 +1279,8 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, * valid */ - if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0) + if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, + HZ * can_sleep) < 0) break; dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n"); @@ -1320,7 +1326,7 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, } if (NCR5380_poll_politely(hostdata, - STATUS_REG, SR_REQ, 0, 5 * HZ) < 0) + STATUS_REG, SR_REQ, 0, 5 * HZ * can_sleep) < 0) break; dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n"); @@ -1395,11 +1401,12 @@ static void do_reset(struct Scsi_Host *instance) * do_abort - abort the currently established nexus by going to * MESSAGE OUT phase and sending an ABORT message. * @instance: relevant scsi host instance + * @can_sleep: 1 or 0 when sleeping is permitted or not, respectively * * Returns 0 on success, negative error code on failure. */ -static int do_abort(struct Scsi_Host *instance) +static int do_abort(struct Scsi_Host *instance, unsigned int can_sleep) { struct NCR5380_hostdata *hostdata = shost_priv(instance); unsigned char *msgptr, phase, tmp; @@ -1419,7 +1426,8 @@ static int do_abort(struct Scsi_Host *instance) * the target sees, so we just handshake. */ - rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ); + rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, + 10 * HZ * can_sleep); if (rc < 0) goto out; @@ -1430,7 +1438,8 @@ static int do_abort(struct Scsi_Host *instance) if (tmp != PHASE_MSGOUT) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); - rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, 0, 3 * HZ); + rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, 0, + 3 * HZ * can_sleep); if (rc < 0) goto out; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); @@ -1440,7 +1449,7 @@ static int do_abort(struct Scsi_Host *instance) msgptr = &tmp; len = 1; phase = PHASE_MSGOUT; - NCR5380_transfer_pio(instance, &phase, &len, &msgptr); + NCR5380_transfer_pio(instance, &phase, &len, &msgptr, can_sleep); if (len) rc = -ENXIO; @@ -1619,12 +1628,12 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, */ if (NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, - BASR_DRQ, BASR_DRQ, HZ) < 0) { + BASR_DRQ, BASR_DRQ, 0) < 0) { result = -1; shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n"); } if (NCR5380_poll_politely(hostdata, STATUS_REG, - SR_REQ, 0, HZ) < 0) { + SR_REQ, 0, 0) < 0) { result = -1; shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n"); } @@ -1636,7 +1645,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, */ if (NCR5380_poll_politely2(hostdata, BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ, - BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) { + BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, 0) < 0) { result = -1; shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n"); } @@ -1733,7 +1742,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) #if (NDEBUG & NDEBUG_NO_DATAOUT) shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n"); sink = 1; - do_abort(instance); + do_abort(instance, 0); cmd->result = DID_ERROR << 16; complete_cmd(instance, cmd); hostdata->connected = NULL; @@ -1789,7 +1798,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) NCR5380_PIO_CHUNK_SIZE); len = transfersize; NCR5380_transfer_pio(instance, &phase, &len, - (unsigned char **)&cmd->SCp.ptr); + (unsigned char **)&cmd->SCp.ptr, + 0); cmd->SCp.this_residual -= transfersize - len; } #ifdef CONFIG_SUN3 @@ -1800,7 +1810,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) case PHASE_MSGIN: len = 1; data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); + NCR5380_transfer_pio(instance, &phase, &len, &data, 0); cmd->SCp.Message = tmp; switch (tmp) { @@ -1841,7 +1851,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) */ NCR5380_write(TARGET_COMMAND_REG, 0); - maybe_release_dma_irq(instance); return; case MESSAGE_REJECT: /* Accept message by clearing ACK */ @@ -1907,7 +1916,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) len = 2; data = extended_msg + 1; phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); + NCR5380_transfer_pio(instance, &phase, &len, &data, 1); dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n", (int)extended_msg[1], (int)extended_msg[2]); @@ -1920,7 +1929,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) data = extended_msg + 3; phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); + NCR5380_transfer_pio(instance, &phase, &len, &data, 1); dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n", len); @@ -1967,13 +1976,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) len = 1; data = &msgout; hostdata->last_message = msgout; - NCR5380_transfer_pio(instance, &phase, &len, &data); + NCR5380_transfer_pio(instance, &phase, &len, &data, 0); if (msgout == ABORT) { hostdata->connected = NULL; hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); cmd->result = DID_ERROR << 16; complete_cmd(instance, cmd); - maybe_release_dma_irq(instance); return; } msgout = NOP; @@ -1986,12 +1994,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) * PSEUDO-DMA architecture we should probably * use the dma transfer function. */ - NCR5380_transfer_pio(instance, &phase, &len, &data); + NCR5380_transfer_pio(instance, &phase, &len, &data, 0); break; case PHASE_STATIN: len = 1; data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); + NCR5380_transfer_pio(instance, &phase, &len, &data, 0); cmd->SCp.Status = tmp; break; default: @@ -2050,7 +2058,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); if (NCR5380_poll_politely(hostdata, - STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) { + STATUS_REG, SR_SEL, 0, 0) < 0) { shost_printk(KERN_ERR, instance, "reselect: !SEL timeout\n"); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); return; @@ -2062,12 +2070,12 @@ static void NCR5380_reselect(struct Scsi_Host *instance) */ if (NCR5380_poll_politely(hostdata, - STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) { + STATUS_REG, SR_REQ, SR_REQ, 0) < 0) { if ((NCR5380_read(STATUS_REG) & (SR_BSY | SR_SEL)) == 0) /* BUS FREE phase */ return; shost_printk(KERN_ERR, instance, "reselect: REQ timeout\n"); - do_abort(instance); + do_abort(instance, 0); return; } @@ -2083,10 +2091,10 @@ static void NCR5380_reselect(struct Scsi_Host *instance) unsigned char *data = msg; unsigned char phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); + NCR5380_transfer_pio(instance, &phase, &len, &data, 0); if (len) { - do_abort(instance); + do_abort(instance, 0); return; } } @@ -2096,7 +2104,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got "); spi_print_msg(msg); printk("\n"); - do_abort(instance); + do_abort(instance, 0); return; } lun = msg[0] & 0x07; @@ -2136,7 +2144,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) * Since we have an established nexus that we can't do anything * with, we must abort it. */ - if (do_abort(instance) == 0) + if (do_abort(instance, 0) == 0) hostdata->busy[target] &= ~(1 << lun); return; } @@ -2283,7 +2291,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); hostdata->connected = NULL; hostdata->dma_len = 0; - if (do_abort(instance) < 0) { + if (do_abort(instance, 0) < 0) { set_host_byte(cmd, DID_ERROR); complete_cmd(instance, cmd); result = FAILED; @@ -2309,7 +2317,6 @@ out: } queue_work(hostdata->work_q, &hostdata->main_task); - maybe_release_dma_irq(instance); spin_unlock_irqrestore(&hostdata->lock, flags); return result; @@ -2365,7 +2372,6 @@ static void bus_reset_cleanup(struct Scsi_Host *instance) hostdata->dma_len = 0; queue_work(hostdata->work_q, &hostdata->main_task); - maybe_release_dma_irq(instance); } /** diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 5935fd6d1a05..8a3b41932288 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -277,7 +277,8 @@ static const char *NCR5380_info(struct Scsi_Host *instance); static void NCR5380_reselect(struct Scsi_Host *instance); static bool NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *); static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); -static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); +static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data, + unsigned int can_sleep); static int NCR5380_poll_politely2(struct NCR5380_hostdata *, unsigned int, u8, u8, unsigned int, u8, u8, unsigned long); diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index e3e157a74988..1b1da162f5f6 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -25,6 +25,7 @@ #include <linux/completion.h> #include <linux/dma-mapping.h> #include <linux/blkdev.h> +#include <linux/compat.h> #include <linux/delay.h> /* ssleep prototype */ #include <linux/kthread.h> #include <linux/uaccess.h> @@ -226,6 +227,12 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) return status; } +struct compat_fib_ioctl { + u32 fibctx; + s32 wait; + compat_uptr_t fib; +}; + /** * next_getadapter_fib - get the next fib * @dev: adapter to use @@ -243,8 +250,19 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) struct list_head * entry; unsigned long flags; - if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) - return -EFAULT; + if (in_compat_syscall()) { + struct compat_fib_ioctl cf; + + if (copy_from_user(&cf, arg, sizeof(struct compat_fib_ioctl))) + return -EFAULT; + + f.fibctx = cf.fibctx; + f.wait = cf.wait; + f.fib = compat_ptr(cf.fib); + } else { + if (copy_from_user(&f, arg, sizeof(struct fib_ioctl))) + return -EFAULT; + } /* * Verify that the HANDLE passed in was a valid AdapterFibContext * diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index b99ca1b0c553..0ae0d1fa2b50 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1448,6 +1448,7 @@ retry_next: break; } scsi_rescan_device(&device->sdev_gendev); + break; default: break; diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 8f3772480582..3168915adaa7 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1182,63 +1182,6 @@ static long aac_cfg_ioctl(struct file *file, return aac_do_ioctl(aac, cmd, (void __user *)arg); } -#ifdef CONFIG_COMPAT -static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg) -{ - long ret; - switch (cmd) { - case FSACTL_MINIPORT_REV_CHECK: - case FSACTL_SENDFIB: - case FSACTL_OPEN_GET_ADAPTER_FIB: - case FSACTL_CLOSE_GET_ADAPTER_FIB: - case FSACTL_SEND_RAW_SRB: - case FSACTL_GET_PCI_INFO: - case FSACTL_QUERY_DISK: - case FSACTL_DELETE_DISK: - case FSACTL_FORCE_DELETE_DISK: - case FSACTL_GET_CONTAINERS: - case FSACTL_SEND_LARGE_FIB: - ret = aac_do_ioctl(dev, cmd, (void __user *)arg); - break; - - case FSACTL_GET_NEXT_ADAPTER_FIB: { - struct fib_ioctl __user *f; - - f = compat_alloc_user_space(sizeof(*f)); - ret = 0; - if (clear_user(f, sizeof(*f))) - ret = -EFAULT; - if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32))) - ret = -EFAULT; - if (!ret) - ret = aac_do_ioctl(dev, cmd, f); - break; - } - - default: - ret = -ENOIOCTLCMD; - break; - } - return ret; -} - -static int aac_compat_ioctl(struct scsi_device *sdev, unsigned int cmd, - void __user *arg) -{ - struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg); -} - -static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long arg) -{ - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - return aac_compat_do_ioctl(file->private_data, cmd, arg); -} -#endif - static ssize_t aac_show_model(struct device *device, struct device_attribute *attr, char *buf) { @@ -1523,7 +1466,7 @@ static const struct file_operations aac_cfg_fops = { .owner = THIS_MODULE, .unlocked_ioctl = aac_cfg_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = aac_compat_cfg_ioctl, + .compat_ioctl = aac_cfg_ioctl, #endif .open = aac_cfg_open, .llseek = noop_llseek, @@ -1536,7 +1479,7 @@ static struct scsi_host_template aac_driver_template = { .info = aac_info, .ioctl = aac_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = aac_compat_ioctl, + .compat_ioctl = aac_ioctl, #endif .queuecommand = aac_queuecommand, .bios_param = aac_biosparm, @@ -1910,11 +1853,9 @@ error_iounmap: } -#if (defined(CONFIG_PM)) -static int aac_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused aac_suspend(struct device *dev) { - - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev); struct aac_dev *aac = (struct aac_dev *)shost->hostdata; scsi_host_block(shost); @@ -1923,29 +1864,14 @@ static int aac_suspend(struct pci_dev *pdev, pm_message_t state) aac_release_resources(aac); - pci_set_drvdata(pdev, shost); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } -static int aac_resume(struct pci_dev *pdev) +static int __maybe_unused aac_resume(struct device *dev) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev); struct aac_dev *aac = (struct aac_dev *)shost->hostdata; - int r; - - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - r = pci_enable_device(pdev); - - if (r) - goto fail_device; - pci_set_master(pdev); if (aac_acquire_resources(aac)) goto fail_device; /* @@ -1960,10 +1886,8 @@ static int aac_resume(struct pci_dev *pdev) fail_device: printk(KERN_INFO "%s%d: resume failed.\n", aac->name, aac->id); scsi_host_put(shost); - pci_disable_device(pdev); return -ENODEV; } -#endif static void aac_shutdown(struct pci_dev *dev) { @@ -2108,15 +2032,14 @@ static struct pci_error_handlers aac_pci_err_handler = { .resume = aac_pci_resume, }; +static SIMPLE_DEV_PM_OPS(aac_pm_ops, aac_suspend, aac_resume); + static struct pci_driver aac_pci_driver = { .name = AAC_DRIVERNAME, .id_table = aac_pci_tbl, .probe = aac_probe_one, .remove = aac_remove_one, -#if (defined(CONFIG_PM)) - .suspend = aac_suspend, - .resume = aac_resume, -#endif + .driver.pm = &aac_pm_ops, .shutdown = aac_shutdown, .err_handler = &aac_pci_err_handler, }; diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index c2c7850ff7b4..79830e77afa9 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -2876,15 +2876,15 @@ static int asc_get_eeprom_string(ushort *serialnum, uchar *cp) static void asc_prt_asc_board_eeprom(struct seq_file *m, struct Scsi_Host *shost) { struct asc_board *boardp = shost_priv(shost); - ASC_DVC_VAR *asc_dvc_varp; ASCEEP_CONFIG *ep; int i; + uchar serialstr[13]; #ifdef CONFIG_ISA + ASC_DVC_VAR *asc_dvc_varp; int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 }; -#endif /* CONFIG_ISA */ - uchar serialstr[13]; asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; +#endif /* CONFIG_ISA */ ep = &boardp->eep_config.asc_eep; seq_printf(m, @@ -3171,7 +3171,6 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost static void asc_prt_driver_conf(struct seq_file *m, struct Scsi_Host *shost) { struct asc_board *boardp = shost_priv(shost); - int chip_scsi_id; seq_printf(m, "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n", @@ -3197,12 +3196,6 @@ static void asc_prt_driver_conf(struct seq_file *m, struct Scsi_Host *shost) boardp->asc_n_io_port); seq_printf(m, " io_port 0x%lx\n", shost->io_port); - - if (ASC_NARROW_BOARD(boardp)) { - chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; - } else { - chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; - } } /* @@ -6111,7 +6104,6 @@ static int AdvISR(ADV_DVC_VAR *asc_dvc) { AdvPortAddr iop_base; uchar int_stat; - ushort target_bit; ADV_CARR_T *free_carrp; __le32 irq_next_vpa; ADV_SCSI_REQ_Q *scsiq; @@ -6198,8 +6190,6 @@ static int AdvISR(ADV_DVC_VAR *asc_dvc) asc_dvc->carr_freelist = free_carrp; asc_dvc->carr_pending_cnt--; - target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id); - /* * Clear request microcode control flag. */ diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index 5a227c03895f..0dc831026e9e 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -152,6 +152,7 @@ static int aha1740_makecode(unchar *sense, unchar *status) retval=DID_ERROR; /* It's an Overrun */ /* If not overrun, assume underrun and * ignore it! */ + break; case 0x00: /* No info, assume no error, should * not occur */ break; diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index 9a515551641c..dd5dfd4f30a5 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -1330,10 +1330,8 @@ const struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t); int ahd_pci_config(struct ahd_softc *, const struct ahd_pci_identity *); int ahd_pci_test_register_access(struct ahd_softc *); -#ifdef CONFIG_PM -void ahd_pci_suspend(struct ahd_softc *); -void ahd_pci_resume(struct ahd_softc *); -#endif +void __maybe_unused ahd_pci_suspend(struct ahd_softc *); +void __maybe_unused ahd_pci_resume(struct ahd_softc *); /************************** SCB and SCB queue management **********************/ void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, @@ -1344,10 +1342,8 @@ struct ahd_softc *ahd_alloc(void *platform_arg, char *name); int ahd_softc_init(struct ahd_softc *); void ahd_controller_info(struct ahd_softc *ahd, char *buf); int ahd_init(struct ahd_softc *ahd); -#ifdef CONFIG_PM -int ahd_suspend(struct ahd_softc *ahd); -void ahd_resume(struct ahd_softc *ahd); -#endif +int __maybe_unused ahd_suspend(struct ahd_softc *ahd); +void __maybe_unused ahd_resume(struct ahd_softc *ahd); int ahd_default_config(struct ahd_softc *ahd); int ahd_parse_vpddata(struct ahd_softc *ahd, struct vpd_config *vpd); diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 98b02e7d38bb..c55b5880eb7e 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -6130,6 +6130,7 @@ ahd_free(struct ahd_softc *ahd) fallthrough; case 2: ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat); + break; case 1: break; case 0: @@ -6542,8 +6543,8 @@ ahd_fini_scbdata(struct ahd_softc *ahd) kfree(hscb_map); } ahd_dma_tag_destroy(ahd, scb_data->hscb_dmat); - /* FALLTHROUGH */ } + fallthrough; case 4: case 3: case 2: @@ -7866,11 +7867,9 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd) ahd->flags &= ~AHD_ALL_INTERRUPTS; } -#ifdef CONFIG_PM -int +int __maybe_unused ahd_suspend(struct ahd_softc *ahd) { - ahd_pause_and_flushwork(ahd); if (LIST_FIRST(&ahd->pending_scbs) != NULL) { @@ -7881,15 +7880,13 @@ ahd_suspend(struct ahd_softc *ahd) return (0); } -void +void __maybe_unused ahd_resume(struct ahd_softc *ahd) { - ahd_reset(ahd, /*reinit*/TRUE); ahd_intr_enable(ahd, TRUE); ahd_restart(ahd); } -#endif /************************** Busy Target Table *********************************/ /* @@ -8911,6 +8908,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) break; case SIU_PFC_ILLEGAL_REQUEST: printk("Illegal request\n"); + break; default: break; } diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index f32398939f74..d413b1c5fdc5 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -2140,7 +2140,6 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd) u_int saved_scbptr; u_int active_scbptr; u_int last_phase; - u_int saved_scsiid; u_int cdb_byte; int retval = SUCCESS; int was_paused; @@ -2254,7 +2253,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd) * passed in command. That command is currently active on the * bus or is in the disconnected state. */ - saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); + ahd_inb(ahd, SAVED_SCSIID); if (last_phase != P_BUSFREE && SCB_GET_TAG(pending_scb) == active_scbptr) { diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 8b891a05d9e7..07b670b80f1b 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -74,11 +74,10 @@ static const struct pci_device_id ahd_linux_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table); -#ifdef CONFIG_PM -static int -ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) +static int __maybe_unused +ahd_linux_pci_dev_suspend(struct device *dev) { - struct ahd_softc *ahd = pci_get_drvdata(pdev); + struct ahd_softc *ahd = dev_get_drvdata(dev); int rc; if ((rc = ahd_suspend(ahd))) @@ -86,39 +85,20 @@ ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) ahd_pci_suspend(ahd); - pci_save_state(pdev); - pci_disable_device(pdev); - - if (mesg.event & PM_EVENT_SLEEP) - pci_set_power_state(pdev, PCI_D3hot); - return rc; } -static int -ahd_linux_pci_dev_resume(struct pci_dev *pdev) +static int __maybe_unused +ahd_linux_pci_dev_resume(struct device *dev) { - struct ahd_softc *ahd = pci_get_drvdata(pdev); - int rc; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - if ((rc = pci_enable_device(pdev))) { - dev_printk(KERN_ERR, &pdev->dev, - "failed to enable device after resume (%d)\n", rc); - return rc; - } - - pci_set_master(pdev); + struct ahd_softc *ahd = dev_get_drvdata(dev); ahd_pci_resume(ahd); ahd_resume(ahd); - return rc; + return 0; } -#endif static void ahd_linux_pci_dev_remove(struct pci_dev *pdev) @@ -224,13 +204,14 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return (0); } +static SIMPLE_DEV_PM_OPS(ahd_linux_pci_dev_pm_ops, + ahd_linux_pci_dev_suspend, + ahd_linux_pci_dev_resume); + static struct pci_driver aic79xx_pci_driver = { .name = "aic79xx", .probe = ahd_linux_pci_dev_probe, -#ifdef CONFIG_PM - .suspend = ahd_linux_pci_dev_suspend, - .resume = ahd_linux_pci_dev_resume, -#endif + .driver.pm = &ahd_linux_pci_dev_pm_ops, .remove = ahd_linux_pci_dev_remove, .id_table = ahd_linux_pci_id_table }; diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 8397ae93f7dd..2f0bdb9225a4 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -377,8 +377,7 @@ ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry) return ahd_pci_map_int(ahd); } -#ifdef CONFIG_PM -void +void __maybe_unused ahd_pci_suspend(struct ahd_softc *ahd) { /* @@ -394,7 +393,7 @@ ahd_pci_suspend(struct ahd_softc *ahd) } -void +void __maybe_unused ahd_pci_resume(struct ahd_softc *ahd) { ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, @@ -404,7 +403,6 @@ ahd_pci_resume(struct ahd_softc *ahd) ahd_pci_write_config(ahd->dev_softc, CSIZE_LATTIME, ahd->suspend_state.pci_state.csize_lattime, /*bytes*/1); } -#endif /* * Perform some simple tests that should catch situations where diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index 88b90f9806c9..11a09798e6b5 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -1134,9 +1134,7 @@ const struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t); int ahc_pci_config(struct ahc_softc *, const struct ahc_pci_identity *); int ahc_pci_test_register_access(struct ahc_softc *); -#ifdef CONFIG_PM -void ahc_pci_resume(struct ahc_softc *ahc); -#endif +void __maybe_unused ahc_pci_resume(struct ahc_softc *ahc); /*************************** EISA/VL Front End ********************************/ struct aic7770_identity *aic7770_find_device(uint32_t); @@ -1160,10 +1158,8 @@ int ahc_chip_init(struct ahc_softc *ahc); int ahc_init(struct ahc_softc *ahc); void ahc_intr_enable(struct ahc_softc *ahc, int enable); void ahc_pause_and_flushwork(struct ahc_softc *ahc); -#ifdef CONFIG_PM -int ahc_suspend(struct ahc_softc *ahc); -int ahc_resume(struct ahc_softc *ahc); -#endif +int __maybe_unused ahc_suspend(struct ahc_softc *ahc); +int __maybe_unused ahc_resume(struct ahc_softc *ahc); void ahc_set_unit(struct ahc_softc *, int); void ahc_set_name(struct ahc_softc *, char *); void ahc_free(struct ahc_softc *ahc); diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 725bb7f58054..b1b852fe940b 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -4478,6 +4478,7 @@ ahc_free(struct ahc_softc *ahc) fallthrough; case 2: ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat); + fallthrough; case 1: break; case 0: @@ -5590,8 +5591,7 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc) ahc->flags &= ~AHC_ALL_INTERRUPTS; } -#ifdef CONFIG_PM -int +int __maybe_unused ahc_suspend(struct ahc_softc *ahc) { @@ -5617,7 +5617,7 @@ ahc_suspend(struct ahc_softc *ahc) return (0); } -int +int __maybe_unused ahc_resume(struct ahc_softc *ahc) { @@ -5626,7 +5626,6 @@ ahc_resume(struct ahc_softc *ahc) ahc_restart(ahc); return (0); } -#endif /************************** Busy Target Table *********************************/ /* * Return the untagged transaction id for a given target/channel lun. @@ -5867,9 +5866,8 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, if ((scb->flags & SCB_ACTIVE) == 0) printk("Inactive SCB in qinfifo\n"); ahc_done(ahc, scb); - - /* FALLTHROUGH */ } + fallthrough; case SEARCH_REMOVE: break; case SEARCH_COUNT: diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 9b293b1f0b71..a07e94fac673 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -121,47 +121,23 @@ static const struct pci_device_id ahc_linux_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table); -#ifdef CONFIG_PM -static int -ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) +static int __maybe_unused +ahc_linux_pci_dev_suspend(struct device *dev) { - struct ahc_softc *ahc = pci_get_drvdata(pdev); - int rc; - - if ((rc = ahc_suspend(ahc))) - return rc; + struct ahc_softc *ahc = dev_get_drvdata(dev); - pci_save_state(pdev); - pci_disable_device(pdev); - - if (mesg.event & PM_EVENT_SLEEP) - pci_set_power_state(pdev, PCI_D3hot); - - return rc; + return ahc_suspend(ahc); } -static int -ahc_linux_pci_dev_resume(struct pci_dev *pdev) +static int __maybe_unused +ahc_linux_pci_dev_resume(struct device *dev) { - struct ahc_softc *ahc = pci_get_drvdata(pdev); - int rc; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - if ((rc = pci_enable_device(pdev))) { - dev_printk(KERN_ERR, &pdev->dev, - "failed to enable device after resume (%d)\n", rc); - return rc; - } - - pci_set_master(pdev); + struct ahc_softc *ahc = dev_get_drvdata(dev); ahc_pci_resume(ahc); return (ahc_resume(ahc)); } -#endif static void ahc_linux_pci_dev_remove(struct pci_dev *pdev) @@ -319,14 +295,14 @@ ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width) } } +static SIMPLE_DEV_PM_OPS(ahc_linux_pci_dev_pm_ops, + ahc_linux_pci_dev_suspend, + ahc_linux_pci_dev_resume); static struct pci_driver aic7xxx_pci_driver = { .name = "aic7xxx", .probe = ahc_linux_pci_dev_probe, -#ifdef CONFIG_PM - .suspend = ahc_linux_pci_dev_suspend, - .resume = ahc_linux_pci_dev_resume, -#endif + .driver.pm = &ahc_linux_pci_dev_pm_ops, .remove = ahc_linux_pci_dev_remove, .id_table = ahc_linux_pci_id_table }; diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 656f680c7802..dab3a6d12c4d 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -2008,8 +2008,7 @@ ahc_pci_chip_init(struct ahc_softc *ahc) return (ahc_chip_init(ahc)); } -#ifdef CONFIG_PM -void +void __maybe_unused ahc_pci_resume(struct ahc_softc *ahc) { /* @@ -2040,7 +2039,6 @@ ahc_pci_resume(struct ahc_softc *ahc) ahc_release_seeprom(&sd); } } -#endif static int ahc_aic785X_setup(struct ahc_softc *ahc) diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index e2d880a5f391..13677973da5c 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -721,6 +721,7 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd) fallthrough; case SAS_LINK_RATE_3_0_GBPS: *speed_mask |= SAS_SPEED_15_DIS; + fallthrough; default: case SAS_LINK_RATE_1_5_GBPS: /* nothing to do */ @@ -739,6 +740,7 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd) switch (pd->min_sata_lrate) { case SAS_LINK_RATE_3_0_GBPS: *speed_mask |= SATA_SPEED_15_DIS; + fallthrough; default: case SAS_LINK_RATE_1_5_GBPS: /* nothing to do */ diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index f923ed019d4a..71d18f607dae 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -269,7 +269,6 @@ Again: case TA_I_T_NEXUS_LOSS: opcode = dl->status_block[0]; goto Again; - break; case TF_INV_CONN_HANDLE: ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_DEVICE_UNKNOWN; @@ -316,6 +315,7 @@ Again: break; case SAS_PROTOCOL_SSP: asd_unbuild_ssp_ascb(ascb); + break; default: break; } @@ -610,6 +610,7 @@ out_err_unmap: break; case SAS_PROTOCOL_SSP: asd_unbuild_ssp_ascb(a); + break; default: break; } diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 5d054d5c70a5..0f6abd233614 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -83,6 +83,7 @@ struct device_attribute; #define PCI_DEVICE_ID_ARECA_1886 0x188A #define ARCMSR_HOURS (1000 * 60 * 60 * 4) #define ARCMSR_MINUTES (1000 * 60 * 60) +#define ARCMSR_DEFAULT_TIMEOUT 90 /* ********************************************************************************** ** diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index e4fdb473b990..4b79661275c9 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -99,6 +99,10 @@ static int set_date_time = 0; module_param(set_date_time, int, S_IRUGO); MODULE_PARM_DESC(set_date_time, " send date, time to iop(0 ~ 1), set_date_time=1(enable), default(=0) is disable"); +static int cmd_timeout = ARCMSR_DEFAULT_TIMEOUT; +module_param(cmd_timeout, int, S_IRUGO); +MODULE_PARM_DESC(cmd_timeout, " scsi cmd timeout(0 ~ 120 sec.), default is 90"); + #define ARCMSR_SLEEPTIME 10 #define ARCMSR_RETRYCOUNT 12 @@ -113,8 +117,8 @@ static int arcmsr_bios_param(struct scsi_device *sdev, static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id); -static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state); -static int arcmsr_resume(struct pci_dev *pdev); +static int __maybe_unused arcmsr_suspend(struct device *dev); +static int __maybe_unused arcmsr_resume(struct device *dev); static void arcmsr_remove(struct pci_dev *pdev); static void arcmsr_shutdown(struct pci_dev *pdev); static void arcmsr_iop_init(struct AdapterControlBlock *acb); @@ -140,6 +144,7 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *); static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb); static void arcmsr_set_iop_datetime(struct timer_list *); +static int arcmsr_slave_config(struct scsi_device *sdev); static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth) { if (queue_depth > ARCMSR_MAX_CMD_PERLUN) @@ -155,6 +160,7 @@ static struct scsi_host_template arcmsr_scsi_host_template = { .eh_abort_handler = arcmsr_abort, .eh_bus_reset_handler = arcmsr_bus_reset, .bios_param = arcmsr_bios_param, + .slave_configure = arcmsr_slave_config, .change_queue_depth = arcmsr_adjust_disk_queue_depth, .can_queue = ARCMSR_DEFAULT_OUTSTANDING_CMD, .this_id = ARCMSR_SCSI_INITIATOR_ID, @@ -216,13 +222,14 @@ static struct pci_device_id arcmsr_device_id_table[] = { }; MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); +static SIMPLE_DEV_PM_OPS(arcmsr_pm_ops, arcmsr_suspend, arcmsr_resume); + static struct pci_driver arcmsr_pci_driver = { .name = "arcmsr", .id_table = arcmsr_device_id_table, .probe = arcmsr_probe, .remove = arcmsr_remove, - .suspend = arcmsr_suspend, - .resume = arcmsr_resume, + .driver.pm = &arcmsr_pm_ops, .shutdown = arcmsr_shutdown, }; /* @@ -1126,8 +1133,9 @@ static void arcmsr_free_irq(struct pci_dev *pdev, pci_free_irq_vectors(pdev); } -static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused arcmsr_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct Scsi_Host *host = pci_get_drvdata(pdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata; @@ -1140,29 +1148,18 @@ static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state) flush_work(&acb->arcmsr_do_message_isr_bh); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); - pci_set_drvdata(pdev, host); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } -static int arcmsr_resume(struct pci_dev *pdev) +static int __maybe_unused arcmsr_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct Scsi_Host *host = pci_get_drvdata(pdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata; - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - if (pci_enable_device(pdev)) { - pr_warn("%s: pci_enable_device error\n", __func__); - return -ENODEV; - } if (arcmsr_set_dma_mask(acb)) goto controller_unregister; - pci_set_master(pdev); if (arcmsr_request_irq(pdev, acb) == FAILED) goto controller_stop; switch (acb->adapter_type) { @@ -1207,9 +1204,7 @@ controller_unregister: if (acb->adapter_type == ACB_ADAPTER_TYPE_F) arcmsr_free_io_queue(acb); arcmsr_unmap_pciregion(acb); - pci_release_regions(pdev); scsi_host_put(host); - pci_disable_device(pdev); return -ENODEV; } @@ -3156,10 +3151,12 @@ message_out: static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb) { - struct list_head *head = &acb->ccb_free_list; + struct list_head *head; struct CommandControlBlock *ccb = NULL; unsigned long flags; + spin_lock_irqsave(&acb->ccblist_lock, flags); + head = &acb->ccb_free_list; if (!list_empty(head)) { ccb = list_entry(head->next, struct CommandControlBlock, list); list_del_init(&ccb->list); @@ -3193,11 +3190,11 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, /* ISO, ECMA, & ANSI versions */ inqdata[4] = 31; /* length of additional data */ - strncpy(&inqdata[8], "Areca ", 8); + memcpy(&inqdata[8], "Areca ", 8); /* Vendor Identification */ - strncpy(&inqdata[16], "RAID controller ", 16); + memcpy(&inqdata[16], "RAID controller ", 16); /* Product Identification */ - strncpy(&inqdata[32], "R001", 4); /* Product Revision */ + memcpy(&inqdata[32], "R001", 4); /* Product Revision */ sg = scsi_sglist(cmd); buffer = kmap_atomic(sg_page(sg)) + sg->offset; @@ -3256,6 +3253,16 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd, static DEF_SCSI_QCMD(arcmsr_queue_command) +static int arcmsr_slave_config(struct scsi_device *sdev) +{ + unsigned int dev_timeout; + + dev_timeout = sdev->request_queue->rq_timeout; + if ((cmd_timeout > 0) && ((cmd_timeout * HZ) > dev_timeout)) + blk_queue_rq_timeout(sdev->request_queue, cmd_timeout * HZ); + return 0; +} + static void arcmsr_get_adapter_config(struct AdapterControlBlock *pACB, uint32_t *rwbuffer) { int count; diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index a82b63a66635..95d7a3586083 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -376,15 +376,11 @@ static int falcon_get_lock(struct Scsi_Host *instance) if (IS_A_TT()) return 1; - if (stdma_is_locked_by(scsi_falcon_intr) && - instance->hostt->can_queue > 1) + if (stdma_is_locked_by(scsi_falcon_intr)) return 1; - if (in_interrupt()) - return stdma_try_lock(scsi_falcon_intr, instance); - - stdma_lock(scsi_falcon_intr, instance); - return 1; + /* stdma_lock() may sleep which means it can't be used here */ + return stdma_try_lock(scsi_falcon_intr, instance); } #ifndef MODULE diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 5c3513a4b450..90fcddb76f46 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -164,7 +164,7 @@ DEVICE_ATTR(beiscsi_active_session_count, S_IRUGO, beiscsi_active_session_disp, NULL); DEVICE_ATTR(beiscsi_free_session_count, S_IRUGO, beiscsi_free_session_disp, NULL); -struct device_attribute *beiscsi_attrs[] = { +static struct device_attribute *beiscsi_attrs[] = { &dev_attr_beiscsi_log_enable, &dev_attr_beiscsi_drvr_ver, &dev_attr_beiscsi_adapter_family, diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 96d6e384b2b2..0d4928567265 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1244,18 +1244,14 @@ beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr, case OC_DEVICE_ID2: return snprintf(buf, PAGE_SIZE, "Obsolete/Unsupported BE2 Adapter Family\n"); - break; case BE_DEVICE_ID2: case OC_DEVICE_ID3: return snprintf(buf, PAGE_SIZE, "BE3-R Adapter Family\n"); - break; case OC_SKH_ID1: return snprintf(buf, PAGE_SIZE, "Skyhawk-R Adapter Family\n"); - break; default: return snprintf(buf, PAGE_SIZE, "Unknown Adapter Family: 0x%x\n", dev_id); - break; } } diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 3486e402bfc1..49a14157f123 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -5671,7 +5671,7 @@ bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port, bfa_fcs_lport_ms_fabric_rscn(port); break; } - /* !!!!!!!!! Fall Through !!!!!!!!!!!!! */ + fallthrough; case FC_RSCN_FORMAT_AREA: case FC_RSCN_FORMAT_DOMAIN: diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 325ad8a592bb..5740302d83ac 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -387,7 +387,7 @@ bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) case IOC_E_PFFAILED: case IOC_E_HWERROR: bfa_ioc_timer_stop(ioc); - /* !!! fall through !!! */ + fallthrough; case IOC_E_TIMEOUT: ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); @@ -437,7 +437,7 @@ bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event) case IOC_E_PFFAILED: case IOC_E_HWERROR: bfa_hb_timer_stop(ioc); - /* !!! fall through !!! */ + fallthrough; case IOC_E_HBFAIL: if (ioc->iocpf.auto_recover) bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry); @@ -3299,6 +3299,7 @@ bfa_ablk_isr(void *cbarg, struct bfi_mbmsg_s *msg) case BFI_ABLK_I2H_PORT_CONFIG: /* update config port mode */ ablk->ioc->port_mode_cfg = rsp->port_mode; + break; case BFI_ABLK_I2H_PF_DELETE: case BFI_ABLK_I2H_PF_UPDATE: @@ -5871,6 +5872,7 @@ bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) break; case BFA_DCONF_SM_EXIT: bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE); + break; case BFA_DCONF_SM_IOCDISABLE: case BFA_DCONF_SM_WR: case BFA_DCONF_SM_FLASH_COMP: diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index b6e8ed757252..b4cea8b06ea1 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -51,7 +51,6 @@ #include <scsi/scsi_tcq.h> #include <scsi/libfc.h> #include <scsi/libfcoe.h> -#include <scsi/fc_encode.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fip.h> diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 08fb7d5d08b3..16bb6d2f98de 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -2088,7 +2088,7 @@ static int __bnx2fc_disable(struct fcoe_ctlr *ctlr) { struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr); - if (interface->enabled == true) { + if (interface->enabled) { if (!ctlr->lp) { pr_err(PFX "__bnx2fc_disable: lport not found\n"); return -ENODEV; @@ -2186,7 +2186,7 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr) struct cnic_fc_npiv_tbl *npiv_tbl; struct fc_lport *lport; - if (interface->enabled == false) { + if (!interface->enabled) { if (!ctlr->lp) { pr_err(PFX "__bnx2fc_enable: lport not found\n"); return -ENODEV; @@ -2277,7 +2277,7 @@ static int bnx2fc_ctlr_enabled(struct fcoe_ctlr_device *cdev) case FCOE_CTLR_UNUSED: default: return -ENOTSUPP; - }; + } } enum bnx2fc_create_link_state { diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 08992095ce7a..b37b0a9ec12d 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -770,7 +770,6 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) } else printk(KERN_ERR PFX "SRR in progress\n"); goto ret_err_rqe; - break; default: break; } diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c index 9010cb6045dc..fe0355c964bc 100644 --- a/drivers/scsi/csiostor/csio_wr.c +++ b/drivers/scsi/csiostor/csio_wr.c @@ -830,6 +830,7 @@ csio_wr_destroy_queues(struct csio_hw *hw, bool cmd) if (flq_idx != -1) csio_q_flid(hw, flq_idx) = CSIO_MAX_QID; } + break; default: break; } diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index fa16894d8758..7b522ff345d5 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1356,7 +1356,7 @@ void selection_timeout_missed(unsigned long ptr) static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, struct ScsiReqBlk* srb) { - u16 s_stat2, return_code; + u16 __maybe_unused s_stat2, return_code; u8 s_stat, scsicommand, i, identify_message; u8 *ptr; dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> srb=%p\n", @@ -2397,7 +2397,6 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, } #endif /* DC395x_LASTPIO */ else { /* xfer pad */ - u8 data = 0, data2 = 0; if (srb->sg_count) { srb->adapter_status = H_OVER_UNDER_RUN; srb->status |= OVER_RUN; @@ -2412,8 +2411,8 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); if (io_dir & DMACMD_DIR) { - data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - data2 = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + DC395x_read8(acb, TRM_S1040_SCSI_FIFO); } else { /* Danger, Robinson: If you find KGs * scattered over the wide disk, the driver @@ -2427,7 +2426,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, /* Danger, Robinson: If you find a collection of Ks on your disk * something broke :-( */ if (io_dir & DMACMD_DIR) - data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + DC395x_read8(acb, TRM_S1040_SCSI_FIFO); else DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K'); } @@ -2989,7 +2988,6 @@ static void reselect(struct AdapterCtlBlk *acb) struct ScsiReqBlk *srb = NULL; u16 rsel_tar_lun_id; u8 id, lun; - u8 arblostflag = 0; dprintkdbg(DBG_0, "reselect: acb=%p\n", acb); clear_fifo(acb, "reselect"); @@ -3011,7 +3009,6 @@ static void reselect(struct AdapterCtlBlk *acb) srb->cmd, dcb->target_id, dcb->target_lun, rsel_tar_lun_id, DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); - arblostflag = 1; /*srb->state |= SRB_DISCONNECT; */ srb->state = SRB_READY; @@ -3042,7 +3039,7 @@ static void reselect(struct AdapterCtlBlk *acb) "disconnection? <%02i-%i>\n", dcb->target_id, dcb->target_lun); - if (dcb->sync_mode & EN_TAG_QUEUEING /*&& !arblostflag */) { + if (dcb->sync_mode & EN_TAG_QUEUEING) { srb = acb->tmp_srb; dcb->active_srb = srb; } else { @@ -3390,11 +3387,9 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, struct scsi_cmnd *p; list_for_each_entry_safe(srb, tmp, &dcb->srb_going_list, list) { - enum dma_data_direction dir; int result; p = srb->cmd; - dir = p->sc_data_direction; result = MK_RES(0, did_flag, 0, 0); printk("G:%p(%02i-%i) ", p, p->device->id, (u8)p->device->lun); diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 308bda2e9c00..ea436a14087f 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -408,12 +408,20 @@ static char print_alua_state(unsigned char state) static int alua_check_sense(struct scsi_device *sdev, struct scsi_sense_hdr *sense_hdr) { + struct alua_dh_data *h = sdev->handler_data; + struct alua_port_group *pg; + switch (sense_hdr->sense_key) { case NOT_READY: if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) { /* * LUN Not Accessible - ALUA state transition */ + rcu_read_lock(); + pg = rcu_dereference(h->pg); + if (pg) + pg->state = SCSI_ACCESS_STATE_TRANSITIONING; + rcu_read_unlock(); alua_check(sdev, false); return NEEDS_RETRY; } @@ -1092,7 +1100,7 @@ static blk_status_t alua_prep_fn(struct scsi_device *sdev, struct request *req) case SCSI_ACCESS_STATE_LBA: return BLK_STS_OK; case SCSI_ACCESS_STATE_TRANSITIONING: - return BLK_STS_RESOURCE; + return BLK_STS_AGAIN; default: req->rq_flags |= RQF_QUIET; return BLK_STS_IOERR; diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h index e30d2f1f5368..ed63f7a9ea54 100644 --- a/drivers/scsi/esas2r/esas2r.h +++ b/drivers/scsi/esas2r/esas2r.h @@ -996,8 +996,9 @@ void esas2r_adapter_tasklet(unsigned long context); irqreturn_t esas2r_interrupt(int irq, void *dev_id); irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id); void esas2r_kickoff_timer(struct esas2r_adapter *a); -int esas2r_suspend(struct pci_dev *pcid, pm_message_t state); -int esas2r_resume(struct pci_dev *pcid); + +extern const struct dev_pm_ops esas2r_pm_ops; + void esas2r_fw_event_off(struct esas2r_adapter *a); void esas2r_fw_event_on(struct esas2r_adapter *a); bool esas2r_nvram_write(struct esas2r_adapter *a, struct esas2r_request *rq, diff --git a/drivers/scsi/esas2r/esas2r_disc.c b/drivers/scsi/esas2r/esas2r_disc.c index 1c079f4300a5..ba42536d1e87 100644 --- a/drivers/scsi/esas2r/esas2r_disc.c +++ b/drivers/scsi/esas2r/esas2r_disc.c @@ -1031,8 +1031,9 @@ static u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr) { struct esas2r_adapter *a = sgc->adapter; - if (sgc->length > ESAS2R_DISC_BUF_LEN) + if (sgc->length > ESAS2R_DISC_BUF_LEN) { esas2r_bugon(); + } *addr = a->uncached_phys + (u64)((u8 *)a->disc_buffer - a->uncached); diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index 09c5c24bf391..c1a5ab662dc8 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -412,10 +412,11 @@ int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid, esas2r_disable_chip_interrupts(a); esas2r_check_adapter(a); - if (!esas2r_init_adapter_hw(a, true)) + if (!esas2r_init_adapter_hw(a, true)) { esas2r_log(ESAS2R_LOG_CRIT, "failed to initialize hardware!"); - else + } else { esas2r_debug("esas2r_init_adapter ok"); + } esas2r_claim_interrupts(a); @@ -640,53 +641,27 @@ void esas2r_kill_adapter(int i) } } -int esas2r_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused esas2r_suspend(struct device *dev) { - struct Scsi_Host *host = pci_get_drvdata(pdev); - u32 device_state; + struct Scsi_Host *host = dev_get_drvdata(dev); struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata; - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "suspending adapter()"); + esas2r_log_dev(ESAS2R_LOG_INFO, dev, "suspending adapter()"); if (!a) return -ENODEV; esas2r_adapter_power_down(a, 1); - device_state = pci_choose_state(pdev, state); - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), - "pci_save_state() called"); - pci_save_state(pdev); - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), - "pci_disable_device() called"); - pci_disable_device(pdev); - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), - "pci_set_power_state() called"); - pci_set_power_state(pdev, device_state); - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "esas2r_suspend(): 0"); + esas2r_log_dev(ESAS2R_LOG_INFO, dev, "esas2r_suspend(): 0"); return 0; } -int esas2r_resume(struct pci_dev *pdev) +static int __maybe_unused esas2r_resume(struct device *dev) { - struct Scsi_Host *host = pci_get_drvdata(pdev); + struct Scsi_Host *host = dev_get_drvdata(dev); struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata; - int rez; - - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "resuming adapter()"); - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), - "pci_set_power_state(PCI_D0) " - "called"); - pci_set_power_state(pdev, PCI_D0); - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), - "pci_enable_wake(PCI_D0, 0) " - "called"); - pci_enable_wake(pdev, PCI_D0, 0); - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), - "pci_restore_state() called"); - pci_restore_state(pdev); - esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), - "pci_enable_device() called"); - rez = pci_enable_device(pdev); - pci_set_master(pdev); + int rez = 0; + + esas2r_log_dev(ESAS2R_LOG_INFO, dev, "resuming adapter()"); if (!a) { rez = -ENODEV; @@ -730,11 +705,13 @@ int esas2r_resume(struct pci_dev *pdev) } error_exit: - esas2r_log_dev(ESAS2R_LOG_CRIT, &(pdev->dev), "esas2r_resume(): %d", + esas2r_log_dev(ESAS2R_LOG_CRIT, dev, "esas2r_resume(): %d", rez); return rez; } +SIMPLE_DEV_PM_OPS(esas2r_pm_ops, esas2r_suspend, esas2r_resume); + bool esas2r_set_degraded_mode(struct esas2r_adapter *a, char *error_str) { set_bit(AF_DEGRADED_MODE, &a->flags); diff --git a/drivers/scsi/esas2r/esas2r_int.c b/drivers/scsi/esas2r/esas2r_int.c index f16d6bcf9bb6..5281d9356327 100644 --- a/drivers/scsi/esas2r/esas2r_int.c +++ b/drivers/scsi/esas2r/esas2r_int.c @@ -688,8 +688,9 @@ static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell) esas2r_local_reset_adapter(a); } - if (!(doorbell & DRBL_FORCE_INT)) + if (!(doorbell & DRBL_FORCE_INT)) { esas2r_trace_exit(); + } } void esas2r_force_interrupt(struct esas2r_adapter *a) @@ -862,10 +863,11 @@ void esas2r_send_reset_ae(struct esas2r_adapter *a, bool pwr_mgt) ae.byflags = 0; ae.bylength = (u8)sizeof(struct atto_vda_ae_hdr); - if (pwr_mgt) + if (pwr_mgt) { esas2r_hdebug("*** sending power management AE ***"); - else + } else { esas2r_hdebug("*** sending reset AE ***"); + } esas2r_queue_fw_event(a, fw_event_vda_ae, &ae, sizeof(union atto_vda_ae)); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 7b49e2e9fcde..a9dd6345f064 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -346,8 +346,7 @@ static struct pci_driver .id_table = esas2r_pci_table, .probe = esas2r_probe, .remove = esas2r_remove, - .suspend = esas2r_suspend, - .resume = esas2r_resume, + .driver.pm = &esas2r_pm_ops, }; static int esas2r_probe(struct pci_dev *pcid, @@ -894,15 +893,11 @@ static void complete_task_management_request(struct esas2r_adapter *a, esas2r_free_request(a, rq); } -/** +/* * Searches the specified queue for the specified queue for the command * to abort. * - * @param [in] a - * @param [in] abort_request - * @param [in] cmd - * t - * @return 0 on failure, 1 if command was not found, 2 if command was found + * Return 0 on failure, 1 if command was not found, 2 if command was found */ static int esas2r_check_active_queue(struct esas2r_adapter *a, struct esas2r_request **abort_request, diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 0f9274960dc6..03bf49adaafe 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1894,7 +1894,6 @@ static int fcoe_device_notification(struct notifier_block *notifier, mutex_unlock(&fcoe_config_mutex); fcoe_ctlr_device_delete(fcoe_ctlr_to_ctlr_dev(ctlr)); goto out; - break; case NETDEV_FEAT_CHANGE: fcoe_netdev_features_change(lport, netdev); break; @@ -2024,7 +2023,7 @@ static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev) case FCOE_CTLR_UNUSED: default: return -ENOTSUPP; - }; + } } /** diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index ffef2c8eddc6..af658aa38fed 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -312,7 +312,7 @@ static ssize_t store_ctlr_mode(struct device *dev, default: LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported.\n"); return -ENOTSUPP; - }; + } } static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO | S_IWUSR, @@ -346,7 +346,7 @@ static ssize_t store_ctlr_enabled(struct device *dev, break; case FCOE_CTLR_UNUSED: return -ENOTSUPP; - }; + } rc = ctlr->f->set_fcoe_ctlr_enabled(ctlr); if (rc) diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 477513dc23b7..69f373b53132 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -39,7 +39,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.6.0.47" +#define DRV_VERSION "1.6.0.53" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " @@ -245,6 +245,7 @@ struct fnic { u32 vlan_hw_insert:1; /* let hw insert the tag */ u32 in_remove:1; /* fnic device in removal */ u32 stop_rx_link_events:1; /* stop proc. rx frames, link events */ + u32 link_events:1; /* set when we get any link event*/ struct completion *remove_wait; /* device remove thread blocks */ diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index e3384afb7cbd..e0cee4dcb439 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -56,6 +56,8 @@ void fnic_handle_link(struct work_struct *work) spin_lock_irqsave(&fnic->fnic_lock, flags); + fnic->link_events = 1; /* less work to just set everytime*/ + if (fnic->stop_rx_link_events) { spin_unlock_irqrestore(&fnic->fnic_lock, flags); return; @@ -73,7 +75,7 @@ void fnic_handle_link(struct work_struct *work) atomic64_set(&fnic->fnic_stats.misc_stats.current_port_speed, new_port_speed); if (old_port_speed != new_port_speed) - shost_printk(KERN_INFO, fnic->lport->host, + FNIC_MAIN_DBG(KERN_INFO, fnic->lport->host, "Current vnic speed set to : %llu\n", new_port_speed); @@ -1349,7 +1351,7 @@ void fnic_handle_fip_timer(struct fnic *fnic) } vlan = list_first_entry(&fnic->vlans, struct fcoe_vlan, list); - shost_printk(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "fip_timer: vlan %d state %d sol_count %d\n", vlan->vid, vlan->state, vlan->sol_count); switch (vlan->state) { @@ -1372,7 +1374,7 @@ void fnic_handle_fip_timer(struct fnic *fnic) * no response on this vlan, remove from the list. * Try the next vlan */ - shost_printk(KERN_INFO, fnic->lport->host, + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, "Dequeue this VLAN ID %d from list\n", vlan->vid); list_del(&vlan->list); @@ -1382,7 +1384,7 @@ void fnic_handle_fip_timer(struct fnic *fnic) /* we exhausted all vlans, restart vlan disc */ spin_unlock_irqrestore(&fnic->vlans_lock, flags); - shost_printk(KERN_INFO, fnic->lport->host, + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, "fip_timer: vlan list empty, " "trigger vlan disc\n"); fnic_event_enq(fnic, FNIC_EVT_START_VLAN_DISC); diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 5f8a7ef8f6a8..186c3ab4456b 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -580,6 +580,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) fnic->lport = lp; fnic->ctlr.lp = lp; + fnic->link_events = 0; + snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME, host->host_no); @@ -740,6 +742,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < FNIC_IO_LOCKS; i++) spin_lock_init(&fnic->io_req_lock[i]); + err = -ENOMEM; fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache); if (!fnic->io_req_pool) goto err_out_free_resources; diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index d1f7b84bbfe8..36744968378f 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -921,10 +921,11 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, case FCPIO_SUCCESS: sc->result = (DID_OK << 16) | icmnd_cmpl->scsi_status; xfer_len = scsi_bufflen(sc); - scsi_set_resid(sc, icmnd_cmpl->residual); - if (icmnd_cmpl->flags & FCPIO_ICMND_CMPL_RESID_UNDER) + if (icmnd_cmpl->flags & FCPIO_ICMND_CMPL_RESID_UNDER) { xfer_len -= icmnd_cmpl->residual; + scsi_set_resid(sc, icmnd_cmpl->residual); + } if (icmnd_cmpl->scsi_status == SAM_STAT_CHECK_CONDITION) atomic64_inc(&fnic_stats->misc_stats.check_condition); @@ -1734,15 +1735,14 @@ void fnic_terminate_rport_io(struct fc_rport *rport) continue; } - cmd_rport = starget_to_rport(scsi_target(sc->device)); - if (rport != cmd_rport) { + io_req = (struct fnic_io_req *)CMD_SP(sc); + if (!io_req) { spin_unlock_irqrestore(io_lock, flags); continue; } - io_req = (struct fnic_io_req *)CMD_SP(sc); - - if (!io_req || rport != cmd_rport) { + cmd_rport = starget_to_rport(scsi_target(sc->device)); + if (rport != cmd_rport) { spin_unlock_irqrestore(io_lock, flags); continue; } @@ -2673,7 +2673,8 @@ void fnic_scsi_abort_io(struct fc_lport *lp) /* Issue firmware reset for fnic, wait for reset to complete */ retry_fw_reset: spin_lock_irqsave(&fnic->fnic_lock, flags); - if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { + if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) && + fnic->link_events) { /* fw reset is in progress, poll for its completion */ spin_unlock_irqrestore(&fnic->fnic_lock, flags); schedule_timeout(msecs_to_jiffies(100)); diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 29e4cdcade72..2df2f38a9b12 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -529,14 +529,14 @@ static inline int generic_NCR5380_precv(struct NCR5380_hostdata *hostdata, if (start == len - 128) { /* Ignore End of DMA interrupt for the final buffer */ if (NCR5380_poll_politely(hostdata, hostdata->c400_ctl_status, - CSR_HOST_BUF_NOT_RDY, 0, HZ / 64) < 0) + CSR_HOST_BUF_NOT_RDY, 0, 0) < 0) break; } else { if (NCR5380_poll_politely2(hostdata, hostdata->c400_ctl_status, CSR_HOST_BUF_NOT_RDY, 0, hostdata->c400_ctl_status, CSR_GATED_53C80_IRQ, - CSR_GATED_53C80_IRQ, HZ / 64) < 0 || + CSR_GATED_53C80_IRQ, 0) < 0 || NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY) break; } @@ -565,7 +565,7 @@ static inline int generic_NCR5380_precv(struct NCR5380_hostdata *hostdata, if (residual == 0 && NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_END_DMA_TRANSFER, BASR_END_DMA_TRANSFER, - HZ / 64) < 0) + 0) < 0) scmd_printk(KERN_ERR, hostdata->connected, "%s: End of DMA timeout\n", __func__); @@ -597,7 +597,7 @@ static inline int generic_NCR5380_psend(struct NCR5380_hostdata *hostdata, CSR_HOST_BUF_NOT_RDY, 0, hostdata->c400_ctl_status, CSR_GATED_53C80_IRQ, - CSR_GATED_53C80_IRQ, HZ / 64) < 0 || + CSR_GATED_53C80_IRQ, 0) < 0 || NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY) { /* Both 128 B buffers are in use */ if (start >= 128) @@ -644,13 +644,13 @@ static inline int generic_NCR5380_psend(struct NCR5380_hostdata *hostdata, if (residual == 0) { if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG, TCR_LAST_BYTE_SENT, TCR_LAST_BYTE_SENT, - HZ / 64) < 0) + 0) < 0) scmd_printk(KERN_ERR, hostdata->connected, "%s: Last Byte Sent timeout\n", __func__); if (NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_END_DMA_TRANSFER, BASR_END_DMA_TRANSFER, - HZ / 64) < 0) + 0) < 0) scmd_printk(KERN_ERR, hostdata->connected, "%s: End of DMA timeout\n", __func__); } diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index a25cfc11c96d..2b28dd405600 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -243,24 +243,6 @@ struct hisi_sas_slot { u16 idx; }; -#define HISI_SAS_DEBUGFS_REG(x) {#x, x} - -struct hisi_sas_debugfs_reg_lu { - char *name; - int off; -}; - -struct hisi_sas_debugfs_reg { - const struct hisi_sas_debugfs_reg_lu *lu; - int count; - int base_off; - union { - u32 (*read_global_reg)(struct hisi_hba *hisi_hba, u32 off); - u32 (*read_port_reg)(struct hisi_hba *hisi_hba, int port, - u32 off); - }; -}; - struct hisi_sas_iost_itct_cache { u32 data[HISI_SAS_IOST_ITCT_CACHE_DW_SZ]; }; @@ -350,15 +332,8 @@ struct hisi_sas_hw { int delay_ms, int timeout_ms); void (*snapshot_prepare)(struct hisi_hba *hisi_hba); void (*snapshot_restore)(struct hisi_hba *hisi_hba); - int (*set_bist)(struct hisi_hba *hisi_hba, bool enable); - void (*read_iost_itct_cache)(struct hisi_hba *hisi_hba, - enum hisi_sas_debugfs_cache_type type, - u32 *cache); int complete_hdr_size; struct scsi_host_template *sht; - - const struct hisi_sas_debugfs_reg *debugfs_reg_array[DEBUGFS_REGS_NUM]; - const struct hisi_sas_debugfs_reg *debugfs_reg_port; }; #define HISI_SAS_MAX_DEBUGFS_DUMP (50) @@ -673,7 +648,4 @@ extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba); extern u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max); extern void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba); extern void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba); -extern void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba); -extern void hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba); -extern void hisi_sas_debugfs_work_handler(struct work_struct *work); #endif diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 274ccf18ce2d..b6d4419c32f2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -591,13 +591,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, dev = hisi_hba->dev; if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) { - /* - * For IOs from upper layer, it may already disable preempt - * in the IO path, if disable preempt again in down(), - * function schedule() will report schedule_bug(), so check - * preemptible() before goto down(). - */ - if (!preemptible()) + if (!gfpflags_allow_blocking(gfp_flags)) return -EINVAL; down(&hisi_hba->sem); @@ -2696,1355 +2690,12 @@ int hisi_sas_probe(struct platform_device *pdev, err_out_register_ha: scsi_remove_host(shost); err_out_ha: - hisi_sas_debugfs_exit(hisi_hba); hisi_sas_free(hisi_hba); scsi_host_put(shost); return rc; } EXPORT_SYMBOL_GPL(hisi_sas_probe); -struct dentry *hisi_sas_debugfs_dir; - -static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba) -{ - int queue_entry_size = hisi_hba->hw->complete_hdr_size; - int dump_index = hisi_hba->debugfs_dump_index; - int i; - - for (i = 0; i < hisi_hba->queue_count; i++) - memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr, - hisi_hba->complete_hdr[i], - HISI_SAS_QUEUE_SLOTS * queue_entry_size); -} - -static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba) -{ - int queue_entry_size = sizeof(struct hisi_sas_cmd_hdr); - int dump_index = hisi_hba->debugfs_dump_index; - int i; - - for (i = 0; i < hisi_hba->queue_count; i++) { - struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr; - int j; - - debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr; - cmd_hdr = hisi_hba->cmd_hdr[i]; - - for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++) - memcpy(&debugfs_cmd_hdr[j], &cmd_hdr[j], - queue_entry_size); - } -} - -static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) -{ - int dump_index = hisi_hba->debugfs_dump_index; - const struct hisi_sas_debugfs_reg *port = - hisi_hba->hw->debugfs_reg_port; - int i, phy_cnt; - u32 offset; - u32 *databuf; - - for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { - databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data; - for (i = 0; i < port->count; i++, databuf++) { - offset = port->base_off + 4 * i; - *databuf = port->read_port_reg(hisi_hba, phy_cnt, - offset); - } - } -} - -static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) -{ - int dump_index = hisi_hba->debugfs_dump_index; - u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data; - const struct hisi_sas_hw *hw = hisi_hba->hw; - const struct hisi_sas_debugfs_reg *global = - hw->debugfs_reg_array[DEBUGFS_GLOBAL]; - int i; - - for (i = 0; i < global->count; i++, databuf++) - *databuf = global->read_global_reg(hisi_hba, 4 * i); -} - -static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba) -{ - int dump_index = hisi_hba->debugfs_dump_index; - u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data; - const struct hisi_sas_hw *hw = hisi_hba->hw; - const struct hisi_sas_debugfs_reg *axi = - hw->debugfs_reg_array[DEBUGFS_AXI]; - int i; - - for (i = 0; i < axi->count; i++, databuf++) - *databuf = axi->read_global_reg(hisi_hba, - 4 * i + axi->base_off); -} - -static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) -{ - int dump_index = hisi_hba->debugfs_dump_index; - u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data; - const struct hisi_sas_hw *hw = hisi_hba->hw; - const struct hisi_sas_debugfs_reg *ras = - hw->debugfs_reg_array[DEBUGFS_RAS]; - int i; - - for (i = 0; i < ras->count; i++, databuf++) - *databuf = ras->read_global_reg(hisi_hba, - 4 * i + ras->base_off); -} - -static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) -{ - int dump_index = hisi_hba->debugfs_dump_index; - void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache; - void *databuf = hisi_hba->debugfs_itct[dump_index].itct; - struct hisi_sas_itct *itct; - int i; - - hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_ITCT_CACHE, - cachebuf); - - itct = hisi_hba->itct; - - for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { - memcpy(databuf, itct, sizeof(struct hisi_sas_itct)); - databuf += sizeof(struct hisi_sas_itct); - } -} - -static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba) -{ - int dump_index = hisi_hba->debugfs_dump_index; - int max_command_entries = HISI_SAS_MAX_COMMANDS; - void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache; - void *databuf = hisi_hba->debugfs_iost[dump_index].iost; - struct hisi_sas_iost *iost; - int i; - - hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_IOST_CACHE, - cachebuf); - - iost = hisi_hba->iost; - - for (i = 0; i < max_command_entries; i++, iost++) { - memcpy(databuf, iost, sizeof(struct hisi_sas_iost)); - databuf += sizeof(struct hisi_sas_iost); - } -} - -static const char * -hisi_sas_debugfs_to_reg_name(int off, int base_off, - const struct hisi_sas_debugfs_reg_lu *lu) -{ - for (; lu->name; lu++) { - if (off == lu->off - base_off) - return lu->name; - } - - return NULL; -} - -static void hisi_sas_debugfs_print_reg(u32 *regs_val, const void *ptr, - struct seq_file *s) -{ - const struct hisi_sas_debugfs_reg *reg = ptr; - int i; - - for (i = 0; i < reg->count; i++) { - int off = i * 4; - const char *name; - - name = hisi_sas_debugfs_to_reg_name(off, reg->base_off, - reg->lu); - - if (name) - seq_printf(s, "0x%08x 0x%08x %s\n", off, - regs_val[i], name); - else - seq_printf(s, "0x%08x 0x%08x\n", off, - regs_val[i]); - } -} - -static int hisi_sas_debugfs_global_show(struct seq_file *s, void *p) -{ - struct hisi_sas_debugfs_regs *global = s->private; - struct hisi_hba *hisi_hba = global->hisi_hba; - const struct hisi_sas_hw *hw = hisi_hba->hw; - const void *reg_global = hw->debugfs_reg_array[DEBUGFS_GLOBAL]; - - hisi_sas_debugfs_print_reg(global->data, - reg_global, s); - - return 0; -} - -static int hisi_sas_debugfs_global_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_global_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_global_fops = { - .open = hisi_sas_debugfs_global_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int hisi_sas_debugfs_axi_show(struct seq_file *s, void *p) -{ - struct hisi_sas_debugfs_regs *axi = s->private; - struct hisi_hba *hisi_hba = axi->hisi_hba; - const struct hisi_sas_hw *hw = hisi_hba->hw; - const void *reg_axi = hw->debugfs_reg_array[DEBUGFS_AXI]; - - hisi_sas_debugfs_print_reg(axi->data, - reg_axi, s); - - return 0; -} - -static int hisi_sas_debugfs_axi_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_axi_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_axi_fops = { - .open = hisi_sas_debugfs_axi_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int hisi_sas_debugfs_ras_show(struct seq_file *s, void *p) -{ - struct hisi_sas_debugfs_regs *ras = s->private; - struct hisi_hba *hisi_hba = ras->hisi_hba; - const struct hisi_sas_hw *hw = hisi_hba->hw; - const void *reg_ras = hw->debugfs_reg_array[DEBUGFS_RAS]; - - hisi_sas_debugfs_print_reg(ras->data, - reg_ras, s); - - return 0; -} - -static int hisi_sas_debugfs_ras_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_ras_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_ras_fops = { - .open = hisi_sas_debugfs_ras_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int hisi_sas_debugfs_port_show(struct seq_file *s, void *p) -{ - struct hisi_sas_debugfs_port *port = s->private; - struct hisi_sas_phy *phy = port->phy; - struct hisi_hba *hisi_hba = phy->hisi_hba; - const struct hisi_sas_hw *hw = hisi_hba->hw; - const struct hisi_sas_debugfs_reg *reg_port = hw->debugfs_reg_port; - - hisi_sas_debugfs_print_reg(port->data, reg_port, s); - - return 0; -} - -static int hisi_sas_debugfs_port_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_port_show, inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_port_fops = { - .open = hisi_sas_debugfs_port_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static void hisi_sas_show_row_64(struct seq_file *s, int index, - int sz, __le64 *ptr) -{ - int i; - - /* completion header size not fixed per HW version */ - seq_printf(s, "index %04d:\n\t", index); - for (i = 1; i <= sz / 8; i++, ptr++) { - seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr)); - if (!(i % 2)) - seq_puts(s, "\n\t"); - } - - seq_puts(s, "\n"); -} - -static void hisi_sas_show_row_32(struct seq_file *s, int index, - int sz, __le32 *ptr) -{ - int i; - - /* completion header size not fixed per HW version */ - seq_printf(s, "index %04d:\n\t", index); - for (i = 1; i <= sz / 4; i++, ptr++) { - seq_printf(s, " 0x%08x", le32_to_cpu(*ptr)); - if (!(i % 4)) - seq_puts(s, "\n\t"); - } - seq_puts(s, "\n"); -} - -static void hisi_sas_cq_show_slot(struct seq_file *s, int slot, - struct hisi_sas_debugfs_cq *debugfs_cq) -{ - struct hisi_sas_cq *cq = debugfs_cq->cq; - struct hisi_hba *hisi_hba = cq->hisi_hba; - __le32 *complete_hdr = debugfs_cq->complete_hdr + - (hisi_hba->hw->complete_hdr_size * slot); - - hisi_sas_show_row_32(s, slot, - hisi_hba->hw->complete_hdr_size, - complete_hdr); -} - -static int hisi_sas_debugfs_cq_show(struct seq_file *s, void *p) -{ - struct hisi_sas_debugfs_cq *debugfs_cq = s->private; - int slot; - - for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) { - hisi_sas_cq_show_slot(s, slot, debugfs_cq); - } - return 0; -} - -static int hisi_sas_debugfs_cq_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_cq_show, inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_cq_fops = { - .open = hisi_sas_debugfs_cq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static void hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr) -{ - struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr; - void *cmd_queue = debugfs_dq->hdr; - __le32 *cmd_hdr = cmd_queue + - sizeof(struct hisi_sas_cmd_hdr) * slot; - - hisi_sas_show_row_32(s, slot, sizeof(struct hisi_sas_cmd_hdr), cmd_hdr); -} - -static int hisi_sas_debugfs_dq_show(struct seq_file *s, void *p) -{ - int slot; - - for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) { - hisi_sas_dq_show_slot(s, slot, s->private); - } - return 0; -} - -static int hisi_sas_debugfs_dq_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_dq_show, inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_dq_fops = { - .open = hisi_sas_debugfs_dq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int hisi_sas_debugfs_iost_show(struct seq_file *s, void *p) -{ - struct hisi_sas_debugfs_iost *debugfs_iost = s->private; - struct hisi_sas_iost *iost = debugfs_iost->iost; - int i, max_command_entries = HISI_SAS_MAX_COMMANDS; - - for (i = 0; i < max_command_entries; i++, iost++) { - __le64 *data = &iost->qw0; - - hisi_sas_show_row_64(s, i, sizeof(*iost), data); - } - - return 0; -} - -static int hisi_sas_debugfs_iost_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_iost_show, inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_iost_fops = { - .open = hisi_sas_debugfs_iost_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int hisi_sas_debugfs_iost_cache_show(struct seq_file *s, void *p) -{ - struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private; - struct hisi_sas_iost_itct_cache *iost_cache = debugfs_iost_cache->cache; - u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; - int i, tab_idx; - __le64 *iost; - - for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, iost_cache++) { - /* - * Data struct of IOST cache: - * Data[1]: BIT0~15: Table index - * Bit16: Valid mask - * Data[2]~[9]: IOST table - */ - tab_idx = (iost_cache->data[1] & 0xffff); - iost = (__le64 *)iost_cache; - - hisi_sas_show_row_64(s, tab_idx, cache_size, iost); - } - - return 0; -} - -static int hisi_sas_debugfs_iost_cache_open(struct inode *inode, - struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_iost_cache_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_iost_cache_fops = { - .open = hisi_sas_debugfs_iost_cache_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int hisi_sas_debugfs_itct_show(struct seq_file *s, void *p) -{ - int i; - struct hisi_sas_debugfs_itct *debugfs_itct = s->private; - struct hisi_sas_itct *itct = debugfs_itct->itct; - - for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { - __le64 *data = &itct->qw0; - - hisi_sas_show_row_64(s, i, sizeof(*itct), data); - } - - return 0; -} - -static int hisi_sas_debugfs_itct_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_itct_show, inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_itct_fops = { - .open = hisi_sas_debugfs_itct_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int hisi_sas_debugfs_itct_cache_show(struct seq_file *s, void *p) -{ - struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private; - struct hisi_sas_iost_itct_cache *itct_cache = debugfs_itct_cache->cache; - u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; - int i, tab_idx; - __le64 *itct; - - for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, itct_cache++) { - /* - * Data struct of ITCT cache: - * Data[1]: BIT0~15: Table index - * Bit16: Valid mask - * Data[2]~[9]: ITCT table - */ - tab_idx = itct_cache->data[1] & 0xffff; - itct = (__le64 *)itct_cache; - - hisi_sas_show_row_64(s, tab_idx, cache_size, itct); - } - - return 0; -} - -static int hisi_sas_debugfs_itct_cache_open(struct inode *inode, - struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_itct_cache_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_itct_cache_fops = { - .open = hisi_sas_debugfs_itct_cache_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) -{ - u64 *debugfs_timestamp; - int dump_index = hisi_hba->debugfs_dump_index; - struct dentry *dump_dentry; - struct dentry *dentry; - char name[256]; - int p; - int c; - int d; - - snprintf(name, 256, "%d", dump_index); - - dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry); - - debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index]; - - debugfs_create_u64("timestamp", 0400, dump_dentry, - debugfs_timestamp); - - debugfs_create_file("global", 0400, dump_dentry, - &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL], - &hisi_sas_debugfs_global_fops); - - /* Create port dir and files */ - dentry = debugfs_create_dir("port", dump_dentry); - for (p = 0; p < hisi_hba->n_phy; p++) { - snprintf(name, 256, "%d", p); - - debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_port_reg[dump_index][p], - &hisi_sas_debugfs_port_fops); - } - - /* Create CQ dir and files */ - dentry = debugfs_create_dir("cq", dump_dentry); - for (c = 0; c < hisi_hba->queue_count; c++) { - snprintf(name, 256, "%d", c); - - debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_cq[dump_index][c], - &hisi_sas_debugfs_cq_fops); - } - - /* Create DQ dir and files */ - dentry = debugfs_create_dir("dq", dump_dentry); - for (d = 0; d < hisi_hba->queue_count; d++) { - snprintf(name, 256, "%d", d); - - debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_dq[dump_index][d], - &hisi_sas_debugfs_dq_fops); - } - - debugfs_create_file("iost", 0400, dump_dentry, - &hisi_hba->debugfs_iost[dump_index], - &hisi_sas_debugfs_iost_fops); - - debugfs_create_file("iost_cache", 0400, dump_dentry, - &hisi_hba->debugfs_iost_cache[dump_index], - &hisi_sas_debugfs_iost_cache_fops); - - debugfs_create_file("itct", 0400, dump_dentry, - &hisi_hba->debugfs_itct[dump_index], - &hisi_sas_debugfs_itct_fops); - - debugfs_create_file("itct_cache", 0400, dump_dentry, - &hisi_hba->debugfs_itct_cache[dump_index], - &hisi_sas_debugfs_itct_cache_fops); - - debugfs_create_file("axi", 0400, dump_dentry, - &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI], - &hisi_sas_debugfs_axi_fops); - - debugfs_create_file("ras", 0400, dump_dentry, - &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS], - &hisi_sas_debugfs_ras_fops); - - return; -} - -static void hisi_sas_debugfs_snapshot_regs(struct hisi_hba *hisi_hba) -{ - hisi_hba->hw->snapshot_prepare(hisi_hba); - - hisi_sas_debugfs_snapshot_global_reg(hisi_hba); - hisi_sas_debugfs_snapshot_port_reg(hisi_hba); - hisi_sas_debugfs_snapshot_axi_reg(hisi_hba); - hisi_sas_debugfs_snapshot_ras_reg(hisi_hba); - hisi_sas_debugfs_snapshot_cq_reg(hisi_hba); - hisi_sas_debugfs_snapshot_dq_reg(hisi_hba); - hisi_sas_debugfs_snapshot_itct_reg(hisi_hba); - hisi_sas_debugfs_snapshot_iost_reg(hisi_hba); - - hisi_sas_debugfs_create_files(hisi_hba); - - hisi_hba->hw->snapshot_restore(hisi_hba); -} - -static ssize_t hisi_sas_debugfs_trigger_dump_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hisi_hba *hisi_hba = file->f_inode->i_private; - char buf[8]; - - if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count) - return -EFAULT; - - if (count > 8) - return -EFAULT; - - if (copy_from_user(buf, user_buf, count)) - return -EFAULT; - - if (buf[0] != '1') - return -EFAULT; - - queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); - - return count; -} - -static const struct file_operations hisi_sas_debugfs_trigger_dump_fops = { - .write = &hisi_sas_debugfs_trigger_dump_write, - .owner = THIS_MODULE, -}; - -enum { - HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL = 0, - HISI_SAS_BIST_LOOPBACK_MODE_SERDES, - HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, -}; - -static const struct { - int value; - char *name; -} hisi_sas_debugfs_loop_linkrate[] = { - { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, - { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, - { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, - { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" }, -}; - -static int hisi_sas_debugfs_bist_linkrate_show(struct seq_file *s, void *p) -{ - struct hisi_hba *hisi_hba = s->private; - int i; - - for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) { - int match = (hisi_hba->debugfs_bist_linkrate == - hisi_sas_debugfs_loop_linkrate[i].value); - - seq_printf(s, "%s%s%s ", match ? "[" : "", - hisi_sas_debugfs_loop_linkrate[i].name, - match ? "]" : ""); - } - seq_puts(s, "\n"); - - return 0; -} - -static ssize_t hisi_sas_debugfs_bist_linkrate_write(struct file *filp, - const char __user *buf, - size_t count, loff_t *ppos) -{ - struct seq_file *m = filp->private_data; - struct hisi_hba *hisi_hba = m->private; - char kbuf[16] = {}, *pkbuf; - bool found = false; - int i; - - if (hisi_hba->debugfs_bist_enable) - return -EPERM; - - if (count >= sizeof(kbuf)) - return -EOVERFLOW; - - if (copy_from_user(kbuf, buf, count)) - return -EINVAL; - - pkbuf = strstrip(kbuf); - - for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) { - if (!strncmp(hisi_sas_debugfs_loop_linkrate[i].name, - pkbuf, 16)) { - hisi_hba->debugfs_bist_linkrate = - hisi_sas_debugfs_loop_linkrate[i].value; - found = true; - break; - } - } - - if (!found) - return -EINVAL; - - return count; -} - -static int hisi_sas_debugfs_bist_linkrate_open(struct inode *inode, - struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_bist_linkrate_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_bist_linkrate_ops = { - .open = hisi_sas_debugfs_bist_linkrate_open, - .read = seq_read, - .write = hisi_sas_debugfs_bist_linkrate_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct { - int value; - char *name; -} hisi_sas_debugfs_loop_code_mode[] = { - { HISI_SAS_BIST_CODE_MODE_PRBS7, "PRBS7" }, - { HISI_SAS_BIST_CODE_MODE_PRBS23, "PRBS23" }, - { HISI_SAS_BIST_CODE_MODE_PRBS31, "PRBS31" }, - { HISI_SAS_BIST_CODE_MODE_JTPAT, "JTPAT" }, - { HISI_SAS_BIST_CODE_MODE_CJTPAT, "CJTPAT" }, - { HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, "SCRAMBED_0" }, - { HISI_SAS_BIST_CODE_MODE_TRAIN, "TRAIN" }, - { HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, "TRAIN_DONE" }, - { HISI_SAS_BIST_CODE_MODE_HFTP, "HFTP" }, - { HISI_SAS_BIST_CODE_MODE_MFTP, "MFTP" }, - { HISI_SAS_BIST_CODE_MODE_LFTP, "LFTP" }, - { HISI_SAS_BIST_CODE_MODE_FIXED_DATA, "FIXED_DATA" }, -}; - -static int hisi_sas_debugfs_bist_code_mode_show(struct seq_file *s, void *p) -{ - struct hisi_hba *hisi_hba = s->private; - int i; - - for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) { - int match = (hisi_hba->debugfs_bist_code_mode == - hisi_sas_debugfs_loop_code_mode[i].value); - - seq_printf(s, "%s%s%s ", match ? "[" : "", - hisi_sas_debugfs_loop_code_mode[i].name, - match ? "]" : ""); - } - seq_puts(s, "\n"); - - return 0; -} - -static ssize_t hisi_sas_debugfs_bist_code_mode_write(struct file *filp, - const char __user *buf, - size_t count, - loff_t *ppos) -{ - struct seq_file *m = filp->private_data; - struct hisi_hba *hisi_hba = m->private; - char kbuf[16] = {}, *pkbuf; - bool found = false; - int i; - - if (hisi_hba->debugfs_bist_enable) - return -EPERM; - - if (count >= sizeof(kbuf)) - return -EINVAL; - - if (copy_from_user(kbuf, buf, count)) - return -EOVERFLOW; - - pkbuf = strstrip(kbuf); - - for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) { - if (!strncmp(hisi_sas_debugfs_loop_code_mode[i].name, - pkbuf, 16)) { - hisi_hba->debugfs_bist_code_mode = - hisi_sas_debugfs_loop_code_mode[i].value; - found = true; - break; - } - } - - if (!found) - return -EINVAL; - - return count; -} - -static int hisi_sas_debugfs_bist_code_mode_open(struct inode *inode, - struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_bist_code_mode_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_bist_code_mode_ops = { - .open = hisi_sas_debugfs_bist_code_mode_open, - .read = seq_read, - .write = hisi_sas_debugfs_bist_code_mode_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static ssize_t hisi_sas_debugfs_bist_phy_write(struct file *filp, - const char __user *buf, - size_t count, loff_t *ppos) -{ - struct seq_file *m = filp->private_data; - struct hisi_hba *hisi_hba = m->private; - unsigned int phy_no; - int val; - - if (hisi_hba->debugfs_bist_enable) - return -EPERM; - - val = kstrtouint_from_user(buf, count, 0, &phy_no); - if (val) - return val; - - if (phy_no >= hisi_hba->n_phy) - return -EINVAL; - - hisi_hba->debugfs_bist_phy_no = phy_no; - - return count; -} - -static int hisi_sas_debugfs_bist_phy_show(struct seq_file *s, void *p) -{ - struct hisi_hba *hisi_hba = s->private; - - seq_printf(s, "%d\n", hisi_hba->debugfs_bist_phy_no); - - return 0; -} - -static int hisi_sas_debugfs_bist_phy_open(struct inode *inode, - struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_bist_phy_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_bist_phy_ops = { - .open = hisi_sas_debugfs_bist_phy_open, - .read = seq_read, - .write = hisi_sas_debugfs_bist_phy_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct { - int value; - char *name; -} hisi_sas_debugfs_loop_modes[] = { - { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" }, - { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" }, - { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" }, -}; - -static int hisi_sas_debugfs_bist_mode_show(struct seq_file *s, void *p) -{ - struct hisi_hba *hisi_hba = s->private; - int i; - - for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) { - int match = (hisi_hba->debugfs_bist_mode == - hisi_sas_debugfs_loop_modes[i].value); - - seq_printf(s, "%s%s%s ", match ? "[" : "", - hisi_sas_debugfs_loop_modes[i].name, - match ? "]" : ""); - } - seq_puts(s, "\n"); - - return 0; -} - -static ssize_t hisi_sas_debugfs_bist_mode_write(struct file *filp, - const char __user *buf, - size_t count, loff_t *ppos) -{ - struct seq_file *m = filp->private_data; - struct hisi_hba *hisi_hba = m->private; - char kbuf[16] = {}, *pkbuf; - bool found = false; - int i; - - if (hisi_hba->debugfs_bist_enable) - return -EPERM; - - if (count >= sizeof(kbuf)) - return -EINVAL; - - if (copy_from_user(kbuf, buf, count)) - return -EOVERFLOW; - - pkbuf = strstrip(kbuf); - - for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) { - if (!strncmp(hisi_sas_debugfs_loop_modes[i].name, pkbuf, 16)) { - hisi_hba->debugfs_bist_mode = - hisi_sas_debugfs_loop_modes[i].value; - found = true; - break; - } - } - - if (!found) - return -EINVAL; - - return count; -} - -static int hisi_sas_debugfs_bist_mode_open(struct inode *inode, - struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_bist_mode_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_bist_mode_ops = { - .open = hisi_sas_debugfs_bist_mode_open, - .read = seq_read, - .write = hisi_sas_debugfs_bist_mode_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static ssize_t hisi_sas_debugfs_bist_enable_write(struct file *filp, - const char __user *buf, - size_t count, loff_t *ppos) -{ - struct seq_file *m = filp->private_data; - struct hisi_hba *hisi_hba = m->private; - unsigned int enable; - int val; - - val = kstrtouint_from_user(buf, count, 0, &enable); - if (val) - return val; - - if (enable > 1) - return -EINVAL; - - if (enable == hisi_hba->debugfs_bist_enable) - return count; - - if (!hisi_hba->hw->set_bist) - return -EPERM; - - val = hisi_hba->hw->set_bist(hisi_hba, enable); - if (val < 0) - return val; - - hisi_hba->debugfs_bist_enable = enable; - - return count; -} - -static int hisi_sas_debugfs_bist_enable_show(struct seq_file *s, void *p) -{ - struct hisi_hba *hisi_hba = s->private; - - seq_printf(s, "%d\n", hisi_hba->debugfs_bist_enable); - - return 0; -} - -static int hisi_sas_debugfs_bist_enable_open(struct inode *inode, - struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_bist_enable_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_bist_enable_ops = { - .open = hisi_sas_debugfs_bist_enable_open, - .read = seq_read, - .write = hisi_sas_debugfs_bist_enable_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct { - char *name; -} hisi_sas_debugfs_ffe_name[FFE_CFG_MAX] = { - { "SAS_1_5_GBPS" }, - { "SAS_3_0_GBPS" }, - { "SAS_6_0_GBPS" }, - { "SAS_12_0_GBPS" }, - { "FFE_RESV" }, - { "SATA_1_5_GBPS" }, - { "SATA_3_0_GBPS" }, - { "SATA_6_0_GBPS" }, -}; - -static ssize_t hisi_sas_debugfs_write(struct file *filp, - const char __user *buf, - size_t count, loff_t *ppos) -{ - struct seq_file *m = filp->private_data; - u32 *val = m->private; - int res; - - res = kstrtouint_from_user(buf, count, 0, val); - if (res) - return res; - - return count; -} - -static int hisi_sas_debugfs_show(struct seq_file *s, void *p) -{ - u32 *val = s->private; - - seq_printf(s, "0x%x\n", *val); - - return 0; -} - -static int hisi_sas_debugfs_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_ops = { - .open = hisi_sas_debugfs_open, - .read = seq_read, - .write = hisi_sas_debugfs_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static ssize_t hisi_sas_debugfs_phy_down_cnt_write(struct file *filp, - const char __user *buf, - size_t count, loff_t *ppos) -{ - struct seq_file *s = filp->private_data; - struct hisi_sas_phy *phy = s->private; - unsigned int set_val; - int res; - - res = kstrtouint_from_user(buf, count, 0, &set_val); - if (res) - return res; - - if (set_val > 0) - return -EINVAL; - - atomic_set(&phy->down_cnt, 0); - - return count; -} - -static int hisi_sas_debugfs_phy_down_cnt_show(struct seq_file *s, void *p) -{ - struct hisi_sas_phy *phy = s->private; - - seq_printf(s, "%d\n", atomic_read(&phy->down_cnt)); - - return 0; -} - -static int hisi_sas_debugfs_phy_down_cnt_open(struct inode *inode, - struct file *filp) -{ - return single_open(filp, hisi_sas_debugfs_phy_down_cnt_show, - inode->i_private); -} - -static const struct file_operations hisi_sas_debugfs_phy_down_cnt_ops = { - .open = hisi_sas_debugfs_phy_down_cnt_open, - .read = seq_read, - .write = hisi_sas_debugfs_phy_down_cnt_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -void hisi_sas_debugfs_work_handler(struct work_struct *work) -{ - struct hisi_hba *hisi_hba = - container_of(work, struct hisi_hba, debugfs_work); - int debugfs_dump_index = hisi_hba->debugfs_dump_index; - struct device *dev = hisi_hba->dev; - u64 timestamp = local_clock(); - - if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) { - dev_warn(dev, "dump count exceeded!\n"); - return; - } - - do_div(timestamp, NSEC_PER_MSEC); - hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp; - - hisi_sas_debugfs_snapshot_regs(hisi_hba); - hisi_hba->debugfs_dump_index++; -} -EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler); - -static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba, int dump_index) -{ - struct device *dev = hisi_hba->dev; - int i; - - devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache); - devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache); - devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost); - devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct); - - for (i = 0; i < hisi_hba->queue_count; i++) - devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr); - - for (i = 0; i < hisi_hba->queue_count; i++) - devm_kfree(dev, - hisi_hba->debugfs_cq[dump_index][i].complete_hdr); - - for (i = 0; i < DEBUGFS_REGS_NUM; i++) - devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data); - - for (i = 0; i < hisi_hba->n_phy; i++) - devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data); -} - -static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba, int dump_index) -{ - const struct hisi_sas_hw *hw = hisi_hba->hw; - struct device *dev = hisi_hba->dev; - int p, c, d, r, i; - size_t sz; - - for (r = 0; r < DEBUGFS_REGS_NUM; r++) { - struct hisi_sas_debugfs_regs *regs = - &hisi_hba->debugfs_regs[dump_index][r]; - - sz = hw->debugfs_reg_array[r]->count * 4; - regs->data = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!regs->data) - goto fail; - regs->hisi_hba = hisi_hba; - } - - sz = hw->debugfs_reg_port->count * 4; - for (p = 0; p < hisi_hba->n_phy; p++) { - struct hisi_sas_debugfs_port *port = - &hisi_hba->debugfs_port_reg[dump_index][p]; - - port->data = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!port->data) - goto fail; - port->phy = &hisi_hba->phy[p]; - } - - sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; - for (c = 0; c < hisi_hba->queue_count; c++) { - struct hisi_sas_debugfs_cq *cq = - &hisi_hba->debugfs_cq[dump_index][c]; - - cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!cq->complete_hdr) - goto fail; - cq->cq = &hisi_hba->cq[c]; - } - - sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; - for (d = 0; d < hisi_hba->queue_count; d++) { - struct hisi_sas_debugfs_dq *dq = - &hisi_hba->debugfs_dq[dump_index][d]; - - dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!dq->hdr) - goto fail; - dq->dq = &hisi_hba->dq[d]; - } - - sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost); - - hisi_hba->debugfs_iost[dump_index].iost = - devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_iost[dump_index].iost) - goto fail; - - sz = HISI_SAS_IOST_ITCT_CACHE_NUM * - sizeof(struct hisi_sas_iost_itct_cache); - - hisi_hba->debugfs_iost_cache[dump_index].cache = - devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_iost_cache[dump_index].cache) - goto fail; - - sz = HISI_SAS_IOST_ITCT_CACHE_NUM * - sizeof(struct hisi_sas_iost_itct_cache); - - hisi_hba->debugfs_itct_cache[dump_index].cache = - devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_itct_cache[dump_index].cache) - goto fail; - - /* New memory allocation must be locate before itct */ - sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); - - hisi_hba->debugfs_itct[dump_index].itct = - devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_itct[dump_index].itct) - goto fail; - - return 0; -fail: - for (i = 0; i < hisi_sas_debugfs_dump_count; i++) - hisi_sas_debugfs_release(hisi_hba, i); - return -ENOMEM; -} - -static void hisi_sas_debugfs_phy_down_cnt_init(struct hisi_hba *hisi_hba) -{ - struct dentry *dir = debugfs_create_dir("phy_down_cnt", - hisi_hba->debugfs_dir); - char name[16]; - int phy_no; - - for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { - snprintf(name, 16, "%d", phy_no); - debugfs_create_file(name, 0600, dir, - &hisi_hba->phy[phy_no], - &hisi_sas_debugfs_phy_down_cnt_ops); - } -} - -static void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba) -{ - struct dentry *ports_dentry; - int phy_no; - - hisi_hba->debugfs_bist_dentry = - debugfs_create_dir("bist", hisi_hba->debugfs_dir); - debugfs_create_file("link_rate", 0600, - hisi_hba->debugfs_bist_dentry, hisi_hba, - &hisi_sas_debugfs_bist_linkrate_ops); - - debugfs_create_file("code_mode", 0600, - hisi_hba->debugfs_bist_dentry, hisi_hba, - &hisi_sas_debugfs_bist_code_mode_ops); - - debugfs_create_file("fixed_code", 0600, - hisi_hba->debugfs_bist_dentry, - &hisi_hba->debugfs_bist_fixed_code[0], - &hisi_sas_debugfs_ops); - - debugfs_create_file("fixed_code_1", 0600, - hisi_hba->debugfs_bist_dentry, - &hisi_hba->debugfs_bist_fixed_code[1], - &hisi_sas_debugfs_ops); - - debugfs_create_file("phy_id", 0600, hisi_hba->debugfs_bist_dentry, - hisi_hba, &hisi_sas_debugfs_bist_phy_ops); - - debugfs_create_u32("cnt", 0600, hisi_hba->debugfs_bist_dentry, - &hisi_hba->debugfs_bist_cnt); - - debugfs_create_file("loopback_mode", 0600, - hisi_hba->debugfs_bist_dentry, - hisi_hba, &hisi_sas_debugfs_bist_mode_ops); - - debugfs_create_file("enable", 0600, hisi_hba->debugfs_bist_dentry, - hisi_hba, &hisi_sas_debugfs_bist_enable_ops); - - ports_dentry = debugfs_create_dir("port", hisi_hba->debugfs_bist_dentry); - - for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { - struct dentry *port_dentry; - struct dentry *ffe_dentry; - char name[256]; - int i; - - snprintf(name, 256, "%d", phy_no); - port_dentry = debugfs_create_dir(name, ports_dentry); - ffe_dentry = debugfs_create_dir("ffe", port_dentry); - for (i = 0; i < FFE_CFG_MAX; i++) { - if (i == FFE_RESV) - continue; - debugfs_create_file(hisi_sas_debugfs_ffe_name[i].name, - 0600, ffe_dentry, - &hisi_hba->debugfs_bist_ffe[phy_no][i], - &hisi_sas_debugfs_ops); - } - } - - hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS; -} - -void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) -{ - struct device *dev = hisi_hba->dev; - int i; - - hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev), - hisi_sas_debugfs_dir); - debugfs_create_file("trigger_dump", 0200, - hisi_hba->debugfs_dir, - hisi_hba, - &hisi_sas_debugfs_trigger_dump_fops); - - /* create bist structures */ - hisi_sas_debugfs_bist_init(hisi_hba); - - hisi_hba->debugfs_dump_dentry = - debugfs_create_dir("dump", hisi_hba->debugfs_dir); - - hisi_sas_debugfs_phy_down_cnt_init(hisi_hba); - - for (i = 0; i < hisi_sas_debugfs_dump_count; i++) { - if (hisi_sas_debugfs_alloc(hisi_hba, i)) { - debugfs_remove_recursive(hisi_hba->debugfs_dir); - dev_dbg(dev, "failed to init debugfs!\n"); - break; - } - } -} -EXPORT_SYMBOL_GPL(hisi_sas_debugfs_init); - -void hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba) -{ - debugfs_remove_recursive(hisi_hba->debugfs_dir); -} -EXPORT_SYMBOL_GPL(hisi_sas_debugfs_exit); - int hisi_sas_remove(struct platform_device *pdev) { struct sas_ha_struct *sha = platform_get_drvdata(pdev); @@ -4073,6 +2724,9 @@ EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dump_count); module_param_named(debugfs_dump_count, hisi_sas_debugfs_dump_count, uint, 0444); MODULE_PARM_DESC(hisi_sas_debugfs_dump_count, "Number of debugfs dumps to allow"); +struct dentry *hisi_sas_debugfs_dir; +EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dir); + static __init int hisi_sas_init(void) { hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 960de375ce69..7c12804b4e1d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -522,6 +522,8 @@ module_param(auto_affine_msi_experimental, bool, 0444); MODULE_PARM_DESC(auto_affine_msi_experimental, "Enable auto-affinity of MSI IRQs as experimental:\n" "default is off"); +static void debugfs_work_handler_v3_hw(struct work_struct *work); + static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { void __iomem *regs = hisi_hba->regs + off; @@ -2409,8 +2411,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) DRV_NAME " phy", hisi_hba); if (rc) { dev_err(dev, "could not request phy interrupt, rc=%d\n", rc); - rc = -ENOENT; - goto free_irq_vectors; + return -ENOENT; } rc = devm_request_irq(dev, pci_irq_vector(pdev, 2), @@ -2418,8 +2419,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) DRV_NAME " channel", hisi_hba); if (rc) { dev_err(dev, "could not request chnl interrupt, rc=%d\n", rc); - rc = -ENOENT; - goto free_irq_vectors; + return -ENOENT; } rc = devm_request_irq(dev, pci_irq_vector(pdev, 11), @@ -2427,8 +2427,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) DRV_NAME " fatal", hisi_hba); if (rc) { dev_err(dev, "could not request fatal interrupt, rc=%d\n", rc); - rc = -ENOENT; - goto free_irq_vectors; + return -ENOENT; } if (hisi_sas_intr_conv) @@ -2449,8 +2448,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) if (rc) { dev_err(dev, "could not request cq%d interrupt, rc=%d\n", i, rc); - rc = -ENOENT; - goto free_irq_vectors; + return -ENOENT; } cq->irq_mask = pci_irq_get_affinity(pdev, i + BASE_VECTORS_V3_HW); if (!cq->irq_mask) { @@ -2460,10 +2458,6 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) } return 0; - -free_irq_vectors: - pci_free_irq_vectors(pdev); - return rc; } static int hisi_sas_v3_init(struct hisi_hba *hisi_hba) @@ -2766,6 +2760,19 @@ static struct device_attribute *host_attrs_v3_hw[] = { NULL }; +#define HISI_SAS_DEBUGFS_REG(x) {#x, x} + +struct hisi_sas_debugfs_reg_lu { + char *name; + int off; +}; + +struct hisi_sas_debugfs_reg { + const struct hisi_sas_debugfs_reg_lu *lu; + int count; + int base_off; +}; + static const struct hisi_sas_debugfs_reg_lu debugfs_port_reg_lu[] = { HISI_SAS_DEBUGFS_REG(PHY_CFG), HISI_SAS_DEBUGFS_REG(HARD_PHY_LINKRATE), @@ -2821,7 +2828,6 @@ static const struct hisi_sas_debugfs_reg debugfs_port_reg = { .lu = debugfs_port_reg_lu, .count = 0x100, .base_off = PORT_BASE, - .read_port_reg = hisi_sas_phy_read32, }; static const struct hisi_sas_debugfs_reg_lu debugfs_global_reg_lu[] = { @@ -2894,7 +2900,6 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_global_reg_lu[] = { static const struct hisi_sas_debugfs_reg debugfs_global_reg = { .lu = debugfs_global_reg_lu, .count = 0x800, - .read_global_reg = hisi_sas_read32, }; static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = { @@ -2909,7 +2914,6 @@ static const struct hisi_sas_debugfs_reg debugfs_axi_reg = { .lu = debugfs_axi_reg_lu, .count = 0x61, .base_off = AXI_MASTER_CFG_BASE, - .read_global_reg = hisi_sas_read32, }; static const struct hisi_sas_debugfs_reg_lu debugfs_ras_reg_lu[] = { @@ -2927,7 +2931,6 @@ static const struct hisi_sas_debugfs_reg debugfs_ras_reg = { .lu = debugfs_ras_reg_lu, .count = 0x10, .base_off = RAS_BASE, - .read_global_reg = hisi_sas_read32, }; static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba) @@ -3147,7 +3150,6 @@ static struct scsi_host_template sht_v3_hw = { }; static const struct hisi_sas_hw hisi_sas_v3_hw = { - .hw_init = hisi_sas_v3_init, .setup_itct = setup_itct_v3_hw, .get_wideport_bitmap = get_wideport_bitmap_v3_hw, .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr), @@ -3170,14 +3172,6 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = { .get_events = phy_get_events_v3_hw, .write_gpio = write_gpio_v3_hw, .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v3_hw, - .debugfs_reg_array[DEBUGFS_GLOBAL] = &debugfs_global_reg, - .debugfs_reg_array[DEBUGFS_AXI] = &debugfs_axi_reg, - .debugfs_reg_array[DEBUGFS_RAS] = &debugfs_ras_reg, - .debugfs_reg_port = &debugfs_port_reg, - .snapshot_prepare = debugfs_snapshot_prepare_v3_hw, - .snapshot_restore = debugfs_snapshot_restore_v3_hw, - .read_iost_itct_cache = read_iost_itct_cache_v3_hw, - .set_bist = debugfs_set_bist_v3_hw, }; static struct Scsi_Host * @@ -3195,7 +3189,7 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev) hisi_hba = shost_priv(shost); INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler); - INIT_WORK(&hisi_hba->debugfs_work, hisi_sas_debugfs_work_handler); + INIT_WORK(&hisi_hba->debugfs_work, debugfs_work_handler_v3_hw); hisi_hba->hw = &hisi_sas_v3_hw; hisi_hba->pci_dev = pdev; hisi_hba->dev = dev; @@ -3223,6 +3217,1196 @@ err_out: return NULL; } +static void debugfs_snapshot_cq_reg_v3_hw(struct hisi_hba *hisi_hba) +{ + int queue_entry_size = hisi_hba->hw->complete_hdr_size; + int dump_index = hisi_hba->debugfs_dump_index; + int i; + + for (i = 0; i < hisi_hba->queue_count; i++) + memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr, + hisi_hba->complete_hdr[i], + HISI_SAS_QUEUE_SLOTS * queue_entry_size); +} + +static void debugfs_snapshot_dq_reg_v3_hw(struct hisi_hba *hisi_hba) +{ + int queue_entry_size = sizeof(struct hisi_sas_cmd_hdr); + int dump_index = hisi_hba->debugfs_dump_index; + int i; + + for (i = 0; i < hisi_hba->queue_count; i++) { + struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr; + int j; + + debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr; + cmd_hdr = hisi_hba->cmd_hdr[i]; + + for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++) + memcpy(&debugfs_cmd_hdr[j], &cmd_hdr[j], + queue_entry_size); + } +} + +static void debugfs_snapshot_port_reg_v3_hw(struct hisi_hba *hisi_hba) +{ + int dump_index = hisi_hba->debugfs_dump_index; + const struct hisi_sas_debugfs_reg *port = &debugfs_port_reg; + int i, phy_cnt; + u32 offset; + u32 *databuf; + + for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { + databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data; + for (i = 0; i < port->count; i++, databuf++) { + offset = port->base_off + 4 * i; + *databuf = hisi_sas_phy_read32(hisi_hba, phy_cnt, + offset); + } + } +} + +static void debugfs_snapshot_global_reg_v3_hw(struct hisi_hba *hisi_hba) +{ + int dump_index = hisi_hba->debugfs_dump_index; + u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data; + int i; + + for (i = 0; i < debugfs_axi_reg.count; i++, databuf++) + *databuf = hisi_sas_read32(hisi_hba, 4 * i); +} + +static void debugfs_snapshot_axi_reg_v3_hw(struct hisi_hba *hisi_hba) +{ + int dump_index = hisi_hba->debugfs_dump_index; + u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data; + const struct hisi_sas_debugfs_reg *axi = &debugfs_axi_reg; + int i; + + for (i = 0; i < axi->count; i++, databuf++) + *databuf = hisi_sas_read32(hisi_hba, 4 * i + axi->base_off); +} + +static void debugfs_snapshot_ras_reg_v3_hw(struct hisi_hba *hisi_hba) +{ + int dump_index = hisi_hba->debugfs_dump_index; + u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data; + const struct hisi_sas_debugfs_reg *ras = &debugfs_ras_reg; + int i; + + for (i = 0; i < ras->count; i++, databuf++) + *databuf = hisi_sas_read32(hisi_hba, 4 * i + ras->base_off); +} + +static void debugfs_snapshot_itct_reg_v3_hw(struct hisi_hba *hisi_hba) +{ + int dump_index = hisi_hba->debugfs_dump_index; + void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache; + void *databuf = hisi_hba->debugfs_itct[dump_index].itct; + struct hisi_sas_itct *itct; + int i; + + read_iost_itct_cache_v3_hw(hisi_hba, HISI_SAS_ITCT_CACHE, cachebuf); + + itct = hisi_hba->itct; + + for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { + memcpy(databuf, itct, sizeof(struct hisi_sas_itct)); + databuf += sizeof(struct hisi_sas_itct); + } +} + +static void debugfs_snapshot_iost_reg_v3_hw(struct hisi_hba *hisi_hba) +{ + int dump_index = hisi_hba->debugfs_dump_index; + int max_command_entries = HISI_SAS_MAX_COMMANDS; + void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache; + void *databuf = hisi_hba->debugfs_iost[dump_index].iost; + struct hisi_sas_iost *iost; + int i; + + read_iost_itct_cache_v3_hw(hisi_hba, HISI_SAS_IOST_CACHE, cachebuf); + + iost = hisi_hba->iost; + + for (i = 0; i < max_command_entries; i++, iost++) { + memcpy(databuf, iost, sizeof(struct hisi_sas_iost)); + databuf += sizeof(struct hisi_sas_iost); + } +} + +static const char * +debugfs_to_reg_name_v3_hw(int off, int base_off, + const struct hisi_sas_debugfs_reg_lu *lu) +{ + for (; lu->name; lu++) { + if (off == lu->off - base_off) + return lu->name; + } + + return NULL; +} + +static void debugfs_print_reg_v3_hw(u32 *regs_val, struct seq_file *s, + const struct hisi_sas_debugfs_reg *reg) +{ + int i; + + for (i = 0; i < reg->count; i++) { + int off = i * 4; + const char *name; + + name = debugfs_to_reg_name_v3_hw(off, reg->base_off, + reg->lu); + + if (name) + seq_printf(s, "0x%08x 0x%08x %s\n", off, + regs_val[i], name); + else + seq_printf(s, "0x%08x 0x%08x\n", off, + regs_val[i]); + } +} + +static int debugfs_global_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_sas_debugfs_regs *global = s->private; + + debugfs_print_reg_v3_hw(global->data, s, + &debugfs_global_reg); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_global_v3_hw); + +static int debugfs_axi_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_sas_debugfs_regs *axi = s->private; + + debugfs_print_reg_v3_hw(axi->data, s, + &debugfs_axi_reg); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_axi_v3_hw); + +static int debugfs_ras_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_sas_debugfs_regs *ras = s->private; + + debugfs_print_reg_v3_hw(ras->data, s, + &debugfs_ras_reg); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_ras_v3_hw); + +static int debugfs_port_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_sas_debugfs_port *port = s->private; + const struct hisi_sas_debugfs_reg *reg_port = &debugfs_port_reg; + + debugfs_print_reg_v3_hw(port->data, s, reg_port); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_port_v3_hw); + +static void debugfs_show_row_64_v3_hw(struct seq_file *s, int index, + int sz, __le64 *ptr) +{ + int i; + + /* completion header size not fixed per HW version */ + seq_printf(s, "index %04d:\n\t", index); + for (i = 1; i <= sz / 8; i++, ptr++) { + seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr)); + if (!(i % 2)) + seq_puts(s, "\n\t"); + } + + seq_puts(s, "\n"); +} + +static void debugfs_show_row_32_v3_hw(struct seq_file *s, int index, + int sz, __le32 *ptr) +{ + int i; + + /* completion header size not fixed per HW version */ + seq_printf(s, "index %04d:\n\t", index); + for (i = 1; i <= sz / 4; i++, ptr++) { + seq_printf(s, " 0x%08x", le32_to_cpu(*ptr)); + if (!(i % 4)) + seq_puts(s, "\n\t"); + } + seq_puts(s, "\n"); +} + +static void debugfs_cq_show_slot_v3_hw(struct seq_file *s, int slot, + struct hisi_sas_debugfs_cq *debugfs_cq) +{ + struct hisi_sas_cq *cq = debugfs_cq->cq; + struct hisi_hba *hisi_hba = cq->hisi_hba; + __le32 *complete_hdr = debugfs_cq->complete_hdr + + (hisi_hba->hw->complete_hdr_size * slot); + + debugfs_show_row_32_v3_hw(s, slot, + hisi_hba->hw->complete_hdr_size, + complete_hdr); +} + +static int debugfs_cq_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_sas_debugfs_cq *debugfs_cq = s->private; + int slot; + + for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) + debugfs_cq_show_slot_v3_hw(s, slot, debugfs_cq); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_cq_v3_hw); + +static void debugfs_dq_show_slot_v3_hw(struct seq_file *s, int slot, + void *dq_ptr) +{ + struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr; + void *cmd_queue = debugfs_dq->hdr; + __le32 *cmd_hdr = cmd_queue + + sizeof(struct hisi_sas_cmd_hdr) * slot; + + debugfs_show_row_32_v3_hw(s, slot, sizeof(struct hisi_sas_cmd_hdr), + cmd_hdr); +} + +static int debugfs_dq_v3_hw_show(struct seq_file *s, void *p) +{ + int slot; + + for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) + debugfs_dq_show_slot_v3_hw(s, slot, s->private); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_dq_v3_hw); + +static int debugfs_iost_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_sas_debugfs_iost *debugfs_iost = s->private; + struct hisi_sas_iost *iost = debugfs_iost->iost; + int i, max_command_entries = HISI_SAS_MAX_COMMANDS; + + for (i = 0; i < max_command_entries; i++, iost++) { + __le64 *data = &iost->qw0; + + debugfs_show_row_64_v3_hw(s, i, sizeof(*iost), data); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_iost_v3_hw); + +static int debugfs_iost_cache_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private; + struct hisi_sas_iost_itct_cache *iost_cache = + debugfs_iost_cache->cache; + u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; + int i, tab_idx; + __le64 *iost; + + for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, iost_cache++) { + /* + * Data struct of IOST cache: + * Data[1]: BIT0~15: Table index + * Bit16: Valid mask + * Data[2]~[9]: IOST table + */ + tab_idx = (iost_cache->data[1] & 0xffff); + iost = (__le64 *)iost_cache; + + debugfs_show_row_64_v3_hw(s, tab_idx, cache_size, iost); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_iost_cache_v3_hw); + +static int debugfs_itct_v3_hw_show(struct seq_file *s, void *p) +{ + int i; + struct hisi_sas_debugfs_itct *debugfs_itct = s->private; + struct hisi_sas_itct *itct = debugfs_itct->itct; + + for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { + __le64 *data = &itct->qw0; + + debugfs_show_row_64_v3_hw(s, i, sizeof(*itct), data); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_itct_v3_hw); + +static int debugfs_itct_cache_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private; + struct hisi_sas_iost_itct_cache *itct_cache = + debugfs_itct_cache->cache; + u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; + int i, tab_idx; + __le64 *itct; + + for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, itct_cache++) { + /* + * Data struct of ITCT cache: + * Data[1]: BIT0~15: Table index + * Bit16: Valid mask + * Data[2]~[9]: ITCT table + */ + tab_idx = itct_cache->data[1] & 0xffff; + itct = (__le64 *)itct_cache; + + debugfs_show_row_64_v3_hw(s, tab_idx, cache_size, itct); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_itct_cache_v3_hw); + +static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba) +{ + u64 *debugfs_timestamp; + int dump_index = hisi_hba->debugfs_dump_index; + struct dentry *dump_dentry; + struct dentry *dentry; + char name[256]; + int p; + int c; + int d; + + snprintf(name, 256, "%d", dump_index); + + dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry); + + debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index]; + + debugfs_create_u64("timestamp", 0400, dump_dentry, + debugfs_timestamp); + + debugfs_create_file("global", 0400, dump_dentry, + &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL], + &debugfs_global_v3_hw_fops); + + /* Create port dir and files */ + dentry = debugfs_create_dir("port", dump_dentry); + for (p = 0; p < hisi_hba->n_phy; p++) { + snprintf(name, 256, "%d", p); + + debugfs_create_file(name, 0400, dentry, + &hisi_hba->debugfs_port_reg[dump_index][p], + &debugfs_port_v3_hw_fops); + } + + /* Create CQ dir and files */ + dentry = debugfs_create_dir("cq", dump_dentry); + for (c = 0; c < hisi_hba->queue_count; c++) { + snprintf(name, 256, "%d", c); + + debugfs_create_file(name, 0400, dentry, + &hisi_hba->debugfs_cq[dump_index][c], + &debugfs_cq_v3_hw_fops); + } + + /* Create DQ dir and files */ + dentry = debugfs_create_dir("dq", dump_dentry); + for (d = 0; d < hisi_hba->queue_count; d++) { + snprintf(name, 256, "%d", d); + + debugfs_create_file(name, 0400, dentry, + &hisi_hba->debugfs_dq[dump_index][d], + &debugfs_dq_v3_hw_fops); + } + + debugfs_create_file("iost", 0400, dump_dentry, + &hisi_hba->debugfs_iost[dump_index], + &debugfs_iost_v3_hw_fops); + + debugfs_create_file("iost_cache", 0400, dump_dentry, + &hisi_hba->debugfs_iost_cache[dump_index], + &debugfs_iost_cache_v3_hw_fops); + + debugfs_create_file("itct", 0400, dump_dentry, + &hisi_hba->debugfs_itct[dump_index], + &debugfs_itct_v3_hw_fops); + + debugfs_create_file("itct_cache", 0400, dump_dentry, + &hisi_hba->debugfs_itct_cache[dump_index], + &debugfs_itct_cache_v3_hw_fops); + + debugfs_create_file("axi", 0400, dump_dentry, + &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI], + &debugfs_axi_v3_hw_fops); + + debugfs_create_file("ras", 0400, dump_dentry, + &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS], + &debugfs_ras_v3_hw_fops); +} + +static void debugfs_snapshot_regs_v3_hw(struct hisi_hba *hisi_hba) +{ + debugfs_snapshot_prepare_v3_hw(hisi_hba); + + debugfs_snapshot_global_reg_v3_hw(hisi_hba); + debugfs_snapshot_port_reg_v3_hw(hisi_hba); + debugfs_snapshot_axi_reg_v3_hw(hisi_hba); + debugfs_snapshot_ras_reg_v3_hw(hisi_hba); + debugfs_snapshot_cq_reg_v3_hw(hisi_hba); + debugfs_snapshot_dq_reg_v3_hw(hisi_hba); + debugfs_snapshot_itct_reg_v3_hw(hisi_hba); + debugfs_snapshot_iost_reg_v3_hw(hisi_hba); + + debugfs_create_files_v3_hw(hisi_hba); + + debugfs_snapshot_restore_v3_hw(hisi_hba); +} + +static ssize_t debugfs_trigger_dump_v3_hw_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hisi_hba *hisi_hba = file->f_inode->i_private; + char buf[8]; + + if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count) + return -EFAULT; + + if (count > 8) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + if (buf[0] != '1') + return -EFAULT; + + queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); + + return count; +} + +static const struct file_operations debugfs_trigger_dump_v3_hw_fops = { + .write = &debugfs_trigger_dump_v3_hw_write, + .owner = THIS_MODULE, +}; + +enum { + HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL = 0, + HISI_SAS_BIST_LOOPBACK_MODE_SERDES, + HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, +}; + +static const struct { + int value; + char *name; +} debugfs_loop_linkrate_v3_hw[] = { + { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, + { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, + { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, + { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" }, +}; + +static int debugfs_bist_linkrate_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + int i; + + for (i = 0; i < ARRAY_SIZE(debugfs_loop_linkrate_v3_hw); i++) { + int match = (hisi_hba->debugfs_bist_linkrate == + debugfs_loop_linkrate_v3_hw[i].value); + + seq_printf(s, "%s%s%s ", match ? "[" : "", + debugfs_loop_linkrate_v3_hw[i].name, + match ? "]" : ""); + } + seq_puts(s, "\n"); + + return 0; +} + +static ssize_t debugfs_bist_linkrate_v3_hw_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + char kbuf[16] = {}, *pkbuf; + bool found = false; + int i; + + if (hisi_hba->debugfs_bist_enable) + return -EPERM; + + if (count >= sizeof(kbuf)) + return -EOVERFLOW; + + if (copy_from_user(kbuf, buf, count)) + return -EINVAL; + + pkbuf = strstrip(kbuf); + + for (i = 0; i < ARRAY_SIZE(debugfs_loop_linkrate_v3_hw); i++) { + if (!strncmp(debugfs_loop_linkrate_v3_hw[i].name, + pkbuf, 16)) { + hisi_hba->debugfs_bist_linkrate = + debugfs_loop_linkrate_v3_hw[i].value; + found = true; + break; + } + } + + if (!found) + return -EINVAL; + + return count; +} + +static int debugfs_bist_linkrate_v3_hw_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, debugfs_bist_linkrate_v3_hw_show, + inode->i_private); +} + +static const struct file_operations debugfs_bist_linkrate_v3_hw_fops = { + .open = debugfs_bist_linkrate_v3_hw_open, + .read = seq_read, + .write = debugfs_bist_linkrate_v3_hw_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct { + int value; + char *name; +} debugfs_loop_code_mode_v3_hw[] = { + { HISI_SAS_BIST_CODE_MODE_PRBS7, "PRBS7" }, + { HISI_SAS_BIST_CODE_MODE_PRBS23, "PRBS23" }, + { HISI_SAS_BIST_CODE_MODE_PRBS31, "PRBS31" }, + { HISI_SAS_BIST_CODE_MODE_JTPAT, "JTPAT" }, + { HISI_SAS_BIST_CODE_MODE_CJTPAT, "CJTPAT" }, + { HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, "SCRAMBED_0" }, + { HISI_SAS_BIST_CODE_MODE_TRAIN, "TRAIN" }, + { HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, "TRAIN_DONE" }, + { HISI_SAS_BIST_CODE_MODE_HFTP, "HFTP" }, + { HISI_SAS_BIST_CODE_MODE_MFTP, "MFTP" }, + { HISI_SAS_BIST_CODE_MODE_LFTP, "LFTP" }, + { HISI_SAS_BIST_CODE_MODE_FIXED_DATA, "FIXED_DATA" }, +}; + +static int debugfs_bist_code_mode_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + int i; + + for (i = 0; i < ARRAY_SIZE(debugfs_loop_code_mode_v3_hw); i++) { + int match = (hisi_hba->debugfs_bist_code_mode == + debugfs_loop_code_mode_v3_hw[i].value); + + seq_printf(s, "%s%s%s ", match ? "[" : "", + debugfs_loop_code_mode_v3_hw[i].name, + match ? "]" : ""); + } + seq_puts(s, "\n"); + + return 0; +} + +static ssize_t debugfs_bist_code_mode_v3_hw_write(struct file *filp, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + char kbuf[16] = {}, *pkbuf; + bool found = false; + int i; + + if (hisi_hba->debugfs_bist_enable) + return -EPERM; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(kbuf, buf, count)) + return -EOVERFLOW; + + pkbuf = strstrip(kbuf); + + for (i = 0; i < ARRAY_SIZE(debugfs_loop_code_mode_v3_hw); i++) { + if (!strncmp(debugfs_loop_code_mode_v3_hw[i].name, + pkbuf, 16)) { + hisi_hba->debugfs_bist_code_mode = + debugfs_loop_code_mode_v3_hw[i].value; + found = true; + break; + } + } + + if (!found) + return -EINVAL; + + return count; +} + +static int debugfs_bist_code_mode_v3_hw_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, debugfs_bist_code_mode_v3_hw_show, + inode->i_private); +} + +static const struct file_operations debugfs_bist_code_mode_v3_hw_fops = { + .open = debugfs_bist_code_mode_v3_hw_open, + .read = seq_read, + .write = debugfs_bist_code_mode_v3_hw_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static ssize_t debugfs_bist_phy_v3_hw_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + unsigned int phy_no; + int val; + + if (hisi_hba->debugfs_bist_enable) + return -EPERM; + + val = kstrtouint_from_user(buf, count, 0, &phy_no); + if (val) + return val; + + if (phy_no >= hisi_hba->n_phy) + return -EINVAL; + + hisi_hba->debugfs_bist_phy_no = phy_no; + + return count; +} + +static int debugfs_bist_phy_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + + seq_printf(s, "%d\n", hisi_hba->debugfs_bist_phy_no); + + return 0; +} + +static int debugfs_bist_phy_v3_hw_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, debugfs_bist_phy_v3_hw_show, + inode->i_private); +} + +static const struct file_operations debugfs_bist_phy_v3_hw_fops = { + .open = debugfs_bist_phy_v3_hw_open, + .read = seq_read, + .write = debugfs_bist_phy_v3_hw_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct { + int value; + char *name; +} debugfs_loop_modes_v3_hw[] = { + { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" }, + { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" }, + { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" }, +}; + +static int debugfs_bist_mode_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + int i; + + for (i = 0; i < ARRAY_SIZE(debugfs_loop_modes_v3_hw); i++) { + int match = (hisi_hba->debugfs_bist_mode == + debugfs_loop_modes_v3_hw[i].value); + + seq_printf(s, "%s%s%s ", match ? "[" : "", + debugfs_loop_modes_v3_hw[i].name, + match ? "]" : ""); + } + seq_puts(s, "\n"); + + return 0; +} + +static ssize_t debugfs_bist_mode_v3_hw_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + char kbuf[16] = {}, *pkbuf; + bool found = false; + int i; + + if (hisi_hba->debugfs_bist_enable) + return -EPERM; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(kbuf, buf, count)) + return -EOVERFLOW; + + pkbuf = strstrip(kbuf); + + for (i = 0; i < ARRAY_SIZE(debugfs_loop_modes_v3_hw); i++) { + if (!strncmp(debugfs_loop_modes_v3_hw[i].name, pkbuf, 16)) { + hisi_hba->debugfs_bist_mode = + debugfs_loop_modes_v3_hw[i].value; + found = true; + break; + } + } + + if (!found) + return -EINVAL; + + return count; +} + +static int debugfs_bist_mode_v3_hw_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, debugfs_bist_mode_v3_hw_show, + inode->i_private); +} + +static const struct file_operations debugfs_bist_mode_v3_hw_fops = { + .open = debugfs_bist_mode_v3_hw_open, + .read = seq_read, + .write = debugfs_bist_mode_v3_hw_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static ssize_t debugfs_bist_enable_v3_hw_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + unsigned int enable; + int val; + + val = kstrtouint_from_user(buf, count, 0, &enable); + if (val) + return val; + + if (enable > 1) + return -EINVAL; + + if (enable == hisi_hba->debugfs_bist_enable) + return count; + + val = debugfs_set_bist_v3_hw(hisi_hba, enable); + if (val < 0) + return val; + + hisi_hba->debugfs_bist_enable = enable; + + return count; +} + +static int debugfs_bist_enable_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + + seq_printf(s, "%d\n", hisi_hba->debugfs_bist_enable); + + return 0; +} + +static int debugfs_bist_enable_v3_hw_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, debugfs_bist_enable_v3_hw_show, + inode->i_private); +} + +static const struct file_operations debugfs_bist_enable_v3_hw_fops = { + .open = debugfs_bist_enable_v3_hw_open, + .read = seq_read, + .write = debugfs_bist_enable_v3_hw_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct { + char *name; +} debugfs_ffe_name_v3_hw[FFE_CFG_MAX] = { + { "SAS_1_5_GBPS" }, + { "SAS_3_0_GBPS" }, + { "SAS_6_0_GBPS" }, + { "SAS_12_0_GBPS" }, + { "FFE_RESV" }, + { "SATA_1_5_GBPS" }, + { "SATA_3_0_GBPS" }, + { "SATA_6_0_GBPS" }, +}; + +static ssize_t debugfs_v3_hw_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + u32 *val = m->private; + int res; + + res = kstrtouint_from_user(buf, count, 0, val); + if (res) + return res; + + return count; +} + +static int debugfs_v3_hw_show(struct seq_file *s, void *p) +{ + u32 *val = s->private; + + seq_printf(s, "0x%x\n", *val); + + return 0; +} + +static int debugfs_v3_hw_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, debugfs_v3_hw_show, + inode->i_private); +} + +static const struct file_operations debugfs_v3_hw_fops = { + .open = debugfs_v3_hw_open, + .read = seq_read, + .write = debugfs_v3_hw_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static ssize_t debugfs_phy_down_cnt_v3_hw_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = filp->private_data; + struct hisi_sas_phy *phy = s->private; + unsigned int set_val; + int res; + + res = kstrtouint_from_user(buf, count, 0, &set_val); + if (res) + return res; + + if (set_val > 0) + return -EINVAL; + + atomic_set(&phy->down_cnt, 0); + + return count; +} + +static int debugfs_phy_down_cnt_v3_hw_show(struct seq_file *s, void *p) +{ + struct hisi_sas_phy *phy = s->private; + + seq_printf(s, "%d\n", atomic_read(&phy->down_cnt)); + + return 0; +} + +static int debugfs_phy_down_cnt_v3_hw_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, debugfs_phy_down_cnt_v3_hw_show, + inode->i_private); +} + +static const struct file_operations debugfs_phy_down_cnt_v3_hw_fops = { + .open = debugfs_phy_down_cnt_v3_hw_open, + .read = seq_read, + .write = debugfs_phy_down_cnt_v3_hw_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static void debugfs_work_handler_v3_hw(struct work_struct *work) +{ + struct hisi_hba *hisi_hba = + container_of(work, struct hisi_hba, debugfs_work); + int debugfs_dump_index = hisi_hba->debugfs_dump_index; + struct device *dev = hisi_hba->dev; + u64 timestamp = local_clock(); + + if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) { + dev_warn(dev, "dump count exceeded!\n"); + return; + } + + do_div(timestamp, NSEC_PER_MSEC); + hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp; + + debugfs_snapshot_regs_v3_hw(hisi_hba); + hisi_hba->debugfs_dump_index++; +} + +static void debugfs_release_v3_hw(struct hisi_hba *hisi_hba, int dump_index) +{ + struct device *dev = hisi_hba->dev; + int i; + + devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache); + devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache); + devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost); + devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct); + + for (i = 0; i < hisi_hba->queue_count; i++) + devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr); + + for (i = 0; i < hisi_hba->queue_count; i++) + devm_kfree(dev, + hisi_hba->debugfs_cq[dump_index][i].complete_hdr); + + for (i = 0; i < DEBUGFS_REGS_NUM; i++) + devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data); + + for (i = 0; i < hisi_hba->n_phy; i++) + devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data); +} + +static const struct hisi_sas_debugfs_reg *debugfs_reg_array_v3_hw[DEBUGFS_REGS_NUM] = { + [DEBUGFS_GLOBAL] = &debugfs_global_reg, + [DEBUGFS_AXI] = &debugfs_axi_reg, + [DEBUGFS_RAS] = &debugfs_ras_reg, +}; + +static int debugfs_alloc_v3_hw(struct hisi_hba *hisi_hba, int dump_index) +{ + const struct hisi_sas_hw *hw = hisi_hba->hw; + struct device *dev = hisi_hba->dev; + int p, c, d, r, i; + size_t sz; + + for (r = 0; r < DEBUGFS_REGS_NUM; r++) { + struct hisi_sas_debugfs_regs *regs = + &hisi_hba->debugfs_regs[dump_index][r]; + + sz = debugfs_reg_array_v3_hw[r]->count * 4; + regs->data = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!regs->data) + goto fail; + regs->hisi_hba = hisi_hba; + } + + sz = debugfs_port_reg.count * 4; + for (p = 0; p < hisi_hba->n_phy; p++) { + struct hisi_sas_debugfs_port *port = + &hisi_hba->debugfs_port_reg[dump_index][p]; + + port->data = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!port->data) + goto fail; + port->phy = &hisi_hba->phy[p]; + } + + sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; + for (c = 0; c < hisi_hba->queue_count; c++) { + struct hisi_sas_debugfs_cq *cq = + &hisi_hba->debugfs_cq[dump_index][c]; + + cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!cq->complete_hdr) + goto fail; + cq->cq = &hisi_hba->cq[c]; + } + + sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; + for (d = 0; d < hisi_hba->queue_count; d++) { + struct hisi_sas_debugfs_dq *dq = + &hisi_hba->debugfs_dq[dump_index][d]; + + dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!dq->hdr) + goto fail; + dq->dq = &hisi_hba->dq[d]; + } + + sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost); + + hisi_hba->debugfs_iost[dump_index].iost = + devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_iost[dump_index].iost) + goto fail; + + sz = HISI_SAS_IOST_ITCT_CACHE_NUM * + sizeof(struct hisi_sas_iost_itct_cache); + + hisi_hba->debugfs_iost_cache[dump_index].cache = + devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_iost_cache[dump_index].cache) + goto fail; + + sz = HISI_SAS_IOST_ITCT_CACHE_NUM * + sizeof(struct hisi_sas_iost_itct_cache); + + hisi_hba->debugfs_itct_cache[dump_index].cache = + devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_itct_cache[dump_index].cache) + goto fail; + + /* New memory allocation must be locate before itct */ + sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); + + hisi_hba->debugfs_itct[dump_index].itct = + devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_itct[dump_index].itct) + goto fail; + + return 0; +fail: + for (i = 0; i < hisi_sas_debugfs_dump_count; i++) + debugfs_release_v3_hw(hisi_hba, i); + return -ENOMEM; +} + +static void debugfs_phy_down_cnt_init_v3_hw(struct hisi_hba *hisi_hba) +{ + struct dentry *dir = debugfs_create_dir("phy_down_cnt", + hisi_hba->debugfs_dir); + char name[16]; + int phy_no; + + for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { + snprintf(name, 16, "%d", phy_no); + debugfs_create_file(name, 0600, dir, + &hisi_hba->phy[phy_no], + &debugfs_phy_down_cnt_v3_hw_fops); + } +} + +static void debugfs_bist_init_v3_hw(struct hisi_hba *hisi_hba) +{ + struct dentry *ports_dentry; + int phy_no; + + hisi_hba->debugfs_bist_dentry = + debugfs_create_dir("bist", hisi_hba->debugfs_dir); + debugfs_create_file("link_rate", 0600, + hisi_hba->debugfs_bist_dentry, hisi_hba, + &debugfs_bist_linkrate_v3_hw_fops); + + debugfs_create_file("code_mode", 0600, + hisi_hba->debugfs_bist_dentry, hisi_hba, + &debugfs_bist_code_mode_v3_hw_fops); + + debugfs_create_file("fixed_code", 0600, + hisi_hba->debugfs_bist_dentry, + &hisi_hba->debugfs_bist_fixed_code[0], + &debugfs_v3_hw_fops); + + debugfs_create_file("fixed_code_1", 0600, + hisi_hba->debugfs_bist_dentry, + &hisi_hba->debugfs_bist_fixed_code[1], + &debugfs_v3_hw_fops); + + debugfs_create_file("phy_id", 0600, hisi_hba->debugfs_bist_dentry, + hisi_hba, &debugfs_bist_phy_v3_hw_fops); + + debugfs_create_u32("cnt", 0600, hisi_hba->debugfs_bist_dentry, + &hisi_hba->debugfs_bist_cnt); + + debugfs_create_file("loopback_mode", 0600, + hisi_hba->debugfs_bist_dentry, + hisi_hba, &debugfs_bist_mode_v3_hw_fops); + + debugfs_create_file("enable", 0600, hisi_hba->debugfs_bist_dentry, + hisi_hba, &debugfs_bist_enable_v3_hw_fops); + + ports_dentry = debugfs_create_dir("port", hisi_hba->debugfs_bist_dentry); + + for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { + struct dentry *port_dentry; + struct dentry *ffe_dentry; + char name[256]; + int i; + + snprintf(name, 256, "%d", phy_no); + port_dentry = debugfs_create_dir(name, ports_dentry); + ffe_dentry = debugfs_create_dir("ffe", port_dentry); + for (i = 0; i < FFE_CFG_MAX; i++) { + if (i == FFE_RESV) + continue; + debugfs_create_file(debugfs_ffe_name_v3_hw[i].name, + 0600, ffe_dentry, + &hisi_hba->debugfs_bist_ffe[phy_no][i], + &debugfs_v3_hw_fops); + } + } + + hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS; +} + +static void debugfs_init_v3_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + int i; + + hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev), + hisi_sas_debugfs_dir); + debugfs_create_file("trigger_dump", 0200, + hisi_hba->debugfs_dir, + hisi_hba, + &debugfs_trigger_dump_v3_hw_fops); + + /* create bist structures */ + debugfs_bist_init_v3_hw(hisi_hba); + + hisi_hba->debugfs_dump_dentry = + debugfs_create_dir("dump", hisi_hba->debugfs_dir); + + debugfs_phy_down_cnt_init_v3_hw(hisi_hba); + + for (i = 0; i < hisi_sas_debugfs_dump_count; i++) { + if (debugfs_alloc_v3_hw(hisi_hba, i)) { + debugfs_remove_recursive(hisi_hba->debugfs_dir); + dev_dbg(dev, "failed to init debugfs!\n"); + break; + } + } +} + +static void debugfs_exit_v3_hw(struct hisi_hba *hisi_hba) +{ + debugfs_remove_recursive(hisi_hba->debugfs_dir); +} + static int hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -3313,21 +4497,21 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) } if (hisi_sas_debugfs_enable) - hisi_sas_debugfs_init(hisi_hba); + debugfs_init_v3_hw(hisi_hba); rc = interrupt_preinit_v3_hw(hisi_hba); if (rc) - goto err_out_ha; + goto err_out_debugfs; dev_err(dev, "%d hw queues\n", shost->nr_hw_queues); rc = scsi_add_host(shost, dev); if (rc) - goto err_out_ha; + goto err_out_free_irq_vectors; rc = sas_register_ha(sha); if (rc) goto err_out_register_ha; - rc = hisi_hba->hw->hw_init(hisi_hba); + rc = hisi_sas_v3_init(hisi_hba); if (rc) goto err_out_register_ha; @@ -3348,8 +4532,12 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) err_out_register_ha: scsi_remove_host(shost); +err_out_free_irq_vectors: + pci_free_irq_vectors(pdev); +err_out_debugfs: + debugfs_exit_v3_hw(hisi_hba); err_out_ha: - hisi_sas_debugfs_exit(hisi_hba); + hisi_sas_free(hisi_hba); scsi_host_put(shost); err_out_regions: pci_release_regions(pdev); @@ -3394,7 +4582,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); hisi_sas_free(hisi_hba); - hisi_sas_debugfs_exit(hisi_hba); + debugfs_exit_v3_hw(hisi_hba); scsi_host_put(shost); } @@ -3445,7 +4633,6 @@ static int _suspend_v3_hw(struct device *device) struct hisi_hba *hisi_hba = sha->lldd_ha; struct device *dev = hisi_hba->dev; struct Scsi_Host *shost = hisi_hba->shost; - pci_power_t device_state; int rc; if (!pdev->pm_cap) { @@ -3471,12 +4658,7 @@ static int _suspend_v3_hw(struct device *device) hisi_sas_init_mem(hisi_hba); - device_state = pci_choose_state(pdev, PMSG_SUSPEND); - dev_warn(dev, "entering operating state [D%d]\n", - device_state); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, device_state); + dev_warn(dev, "entering suspend state\n"); hisi_sas_release_tasks(hisi_hba); @@ -3496,16 +4678,7 @@ static int _resume_v3_hw(struct device *device) dev_warn(dev, "resuming from operating state [D%d]\n", device_state); - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - rc = pci_enable_device(pdev); - if (rc) { - dev_err(dev, "enable device failed during resume (%d)\n", rc); - return rc; - } - pci_set_master(pdev); scsi_unblock_requests(shost); clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); @@ -3513,17 +4686,16 @@ static int _resume_v3_hw(struct device *device) rc = hw_init_v3_hw(hisi_hba); if (rc) { scsi_remove_host(shost); - pci_disable_device(pdev); return rc; } - hisi_hba->hw->phys_init(hisi_hba); + phys_init_v3_hw(hisi_hba); sas_resume_ha(sha); clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); return 0; } -static int suspend_v3_hw(struct device *device) +static int __maybe_unused suspend_v3_hw(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct sas_ha_struct *sha = pci_get_drvdata(pdev); @@ -3539,7 +4711,7 @@ static int suspend_v3_hw(struct device *device) return rc; } -static int resume_v3_hw(struct device *device) +static int __maybe_unused resume_v3_hw(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct sas_ha_struct *sha = pci_get_drvdata(pdev); @@ -3562,21 +4734,10 @@ static const struct pci_error_handlers hisi_sas_err_handler = { .reset_done = hisi_sas_reset_done_v3_hw, }; -static int runtime_suspend_v3_hw(struct device *dev) -{ - return suspend_v3_hw(dev); -} - -static int runtime_resume_v3_hw(struct device *dev) -{ - return resume_v3_hw(dev); -} - -static const struct dev_pm_ops hisi_sas_v3_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(suspend_v3_hw, resume_v3_hw) - SET_RUNTIME_PM_OPS(runtime_suspend_v3_hw, - runtime_resume_v3_hw, NULL) -}; +static UNIVERSAL_DEV_PM_OPS(hisi_sas_v3_pm_ops, + suspend_v3_hw, + resume_v3_hw, + NULL); static struct pci_driver sas_v3_pci_driver = { .name = DRV_NAME, diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8df70c92911d..f4d3747cfa0b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3881,8 +3881,6 @@ static unsigned char hpsa_volume_offline(struct ctlr_info *h, u8 sense_key, asc, ascq; int sense_len; int rc, ldstat = 0; - u16 cmd_status; - u8 scsi_status; #define ASC_LUN_NOT_READY 0x04 #define ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS 0x04 #define ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ 0x02 @@ -3902,8 +3900,6 @@ static unsigned char hpsa_volume_offline(struct ctlr_info *h, else sense_len = c->err_info->SenseLen; decode_sense_data(sense, sense_len, &sense_key, &asc, &ascq); - cmd_status = c->err_info->CommandStatus; - scsi_status = c->err_info->ScsiStatus; cmd_free(h, c); /* Determine the reason for not ready state */ @@ -4351,7 +4347,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) u32 ndev_allocated = 0; struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; int ncurrent = 0; - int i, n_ext_target_devs, ndevs_to_allocate; + int i, ndevs_to_allocate; int raid_ctlr_position; bool physical_device; DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); @@ -4416,7 +4412,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) raid_ctlr_position = nphysicals + nlogicals; /* adjust our table of devices */ - n_ext_target_devs = 0; for (i = 0; i < nphysicals + nlogicals + 1; i++) { u8 *lunaddrbytes, is_OBDR = 0; int rc = 0; @@ -4580,7 +4575,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, struct scsi_cmnd *cmd) { struct scatterlist *sg; - int use_sg, i, sg_limit, chained, last_sg; + int use_sg, i, sg_limit, chained; struct SGDescriptor *curr_sg; BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); @@ -4602,7 +4597,6 @@ static int hpsa_scatter_gather(struct ctlr_info *h, curr_sg = cp->SG; chained = use_sg > h->max_cmd_sg_entries; sg_limit = chained ? h->max_cmd_sg_entries - 1 : use_sg; - last_sg = scsi_sg_count(cmd) - 1; scsi_for_each_sg(cmd, sg, sg_limit, i) { hpsa_set_sg_descriptor(curr_sg, sg); curr_sg++; @@ -7442,7 +7436,6 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) dev_warn(&pdev->dev, "base address is invalid\n"); return -1; - break; } } if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0) @@ -8636,7 +8629,7 @@ static struct ctlr_info *hpda_alloc_ctlr_info(void) static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - int dac, rc; + int rc; struct ctlr_info *h; int try_soft_reset = 0; unsigned long flags; @@ -8712,13 +8705,9 @@ reinit_after_soft_reset: /* configure PCI DMA stuff */ rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); - if (rc == 0) { - dac = 1; - } else { + if (rc != 0) { rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc == 0) { - dac = 0; - } else { + if (rc != 0) { dev_err(&pdev->dev, "no suitable DMA available\n"); goto clean3; /* shost, pci, lu, aer/h */ } @@ -9092,25 +9081,27 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpda_free_ctlr_info(h); /* init_one 1 */ } -static int hpsa_suspend(__attribute__((unused)) struct pci_dev *pdev, - __attribute__((unused)) pm_message_t state) +static int __maybe_unused hpsa_suspend( + __attribute__((unused)) struct device *dev) { return -ENOSYS; } -static int hpsa_resume(__attribute__((unused)) struct pci_dev *pdev) +static int __maybe_unused hpsa_resume + (__attribute__((unused)) struct device *dev) { return -ENOSYS; } +static SIMPLE_DEV_PM_OPS(hpsa_pm_ops, hpsa_suspend, hpsa_resume); + static struct pci_driver hpsa_pci_driver = { .name = HPSA, .probe = hpsa_init_one, .remove = hpsa_remove_one, .id_table = hpsa_pci_device_id, /* id_table */ .shutdown = hpsa_shutdown, - .suspend = hpsa_suspend, - .resume = hpsa_resume, + .driver.pm = &hpsa_pm_ops, }; /* Fill in bucket_map[], given nsgs (the max number of @@ -9299,10 +9290,9 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) } else if (trans_support & CFGTBL_Trans_io_accel2) { u64 cfg_offset, cfg_base_addr_index; u32 bft2_offset, cfg_base_addr; - int rc; - rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr, - &cfg_base_addr_index, &cfg_offset); + hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr, + &cfg_base_addr_index, &cfg_offset); BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) != 64); bft2[15] = h->ioaccel_maxsg + HPSA_IOACCEL2_HEADER_SZ; calc_bucket_map(bft2, ARRAY_SIZE(bft2), h->ioaccel_maxsg, diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 6a2561f26e38..db4c7a7ff4dd 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -758,7 +758,6 @@ static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag, scp->result = SAM_STAT_CHECK_CONDITION; memcpy(scp->sense_buffer, &req->sg_list, SCSI_SENSE_BUFFERSIZE); goto skip_resid; - break; default: scp->result = DRIVER_INVALID << 24 | DID_ABORT << 16; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 070cf516b98f..42e4d35e0d35 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -138,6 +138,31 @@ static void ibmvfc_tgt_move_login(struct ibmvfc_target *); static const char *unknown_error = "unknown error"; +static int ibmvfc_check_caps(struct ibmvfc_host *vhost, unsigned long cap_flags) +{ + u64 host_caps = be64_to_cpu(vhost->login_buf->resp.capabilities); + + return (host_caps & cap_flags) ? 1 : 0; +} + +static struct ibmvfc_fcp_cmd_iu *ibmvfc_get_fcp_iu(struct ibmvfc_host *vhost, + struct ibmvfc_cmd *vfc_cmd) +{ + if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) + return &vfc_cmd->v2.iu; + else + return &vfc_cmd->v1.iu; +} + +static struct ibmvfc_fcp_rsp *ibmvfc_get_fcp_rsp(struct ibmvfc_host *vhost, + struct ibmvfc_cmd *vfc_cmd) +{ + if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) + return &vfc_cmd->v2.rsp; + else + return &vfc_cmd->v1.rsp; +} + #ifdef CONFIG_SCSI_IBMVFC_TRACE /** * ibmvfc_trc_start - Log a start trace entry @@ -149,6 +174,7 @@ static void ibmvfc_trc_start(struct ibmvfc_event *evt) struct ibmvfc_host *vhost = evt->vhost; struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd; struct ibmvfc_mad_common *mad = &evt->iu.mad_common; + struct ibmvfc_fcp_cmd_iu *iu = ibmvfc_get_fcp_iu(vhost, vfc_cmd); struct ibmvfc_trace_entry *entry; entry = &vhost->trace[vhost->trace_index++]; @@ -159,11 +185,11 @@ static void ibmvfc_trc_start(struct ibmvfc_event *evt) switch (entry->fmt) { case IBMVFC_CMD_FORMAT: - entry->op_code = vfc_cmd->iu.cdb[0]; + entry->op_code = iu->cdb[0]; entry->scsi_id = be64_to_cpu(vfc_cmd->tgt_scsi_id); - entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); - entry->tmf_flags = vfc_cmd->iu.tmf_flags; - entry->u.start.xfer_len = be32_to_cpu(vfc_cmd->iu.xfer_len); + entry->lun = scsilun_to_int(&iu->lun); + entry->tmf_flags = iu->tmf_flags; + entry->u.start.xfer_len = be32_to_cpu(iu->xfer_len); break; case IBMVFC_MAD_FORMAT: entry->op_code = be32_to_cpu(mad->opcode); @@ -183,6 +209,8 @@ static void ibmvfc_trc_end(struct ibmvfc_event *evt) struct ibmvfc_host *vhost = evt->vhost; struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; struct ibmvfc_mad_common *mad = &evt->xfer_iu->mad_common; + struct ibmvfc_fcp_cmd_iu *iu = ibmvfc_get_fcp_iu(vhost, vfc_cmd); + struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(vhost, vfc_cmd); struct ibmvfc_trace_entry *entry = &vhost->trace[vhost->trace_index++]; entry->evt = evt; @@ -192,15 +220,15 @@ static void ibmvfc_trc_end(struct ibmvfc_event *evt) switch (entry->fmt) { case IBMVFC_CMD_FORMAT: - entry->op_code = vfc_cmd->iu.cdb[0]; + entry->op_code = iu->cdb[0]; entry->scsi_id = be64_to_cpu(vfc_cmd->tgt_scsi_id); - entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); - entry->tmf_flags = vfc_cmd->iu.tmf_flags; + entry->lun = scsilun_to_int(&iu->lun); + entry->tmf_flags = iu->tmf_flags; entry->u.end.status = be16_to_cpu(vfc_cmd->status); entry->u.end.error = be16_to_cpu(vfc_cmd->error); - entry->u.end.fcp_rsp_flags = vfc_cmd->rsp.flags; - entry->u.end.rsp_code = vfc_cmd->rsp.data.info.rsp_code; - entry->u.end.scsi_status = vfc_cmd->rsp.scsi_status; + entry->u.end.fcp_rsp_flags = rsp->flags; + entry->u.end.rsp_code = rsp->data.info.rsp_code; + entry->u.end.scsi_status = rsp->scsi_status; break; case IBMVFC_MAD_FORMAT: entry->op_code = be32_to_cpu(mad->opcode); @@ -260,10 +288,10 @@ static const char *ibmvfc_get_cmd_error(u16 status, u16 error) * Return value: * SCSI result value to return for completed command **/ -static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd) +static int ibmvfc_get_err_result(struct ibmvfc_host *vhost, struct ibmvfc_cmd *vfc_cmd) { int err; - struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; + struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(vhost, vfc_cmd); int fc_rsp_len = be32_to_cpu(rsp->fcp_rsp_len); if ((rsp->flags & FCP_RSP_LEN_VALID) && @@ -1227,7 +1255,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) login_info->flags |= cpu_to_be16(IBMVFC_CLIENT_MIGRATED); login_info->max_cmds = cpu_to_be32(max_requests + IBMVFC_NUM_INTERNAL_REQ); - login_info->capabilities = cpu_to_be64(IBMVFC_CAN_MIGRATE); + login_info->capabilities = cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_SEND_VF_WWPN); login_info->async.va = cpu_to_be64(vhost->async_crq.msg_token); login_info->async.len = cpu_to_be32(vhost->async_crq.size * sizeof(*vhost->async_crq.msgs)); strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); @@ -1378,6 +1406,7 @@ static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd, int sg_mapped; struct srp_direct_buf *data = &vfc_cmd->ioba; struct ibmvfc_host *vhost = dev_get_drvdata(dev); + struct ibmvfc_fcp_cmd_iu *iu = ibmvfc_get_fcp_iu(evt->vhost, vfc_cmd); if (cls3_error) vfc_cmd->flags |= cpu_to_be16(IBMVFC_CLASS_3_ERR); @@ -1394,10 +1423,10 @@ static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd, if (scmd->sc_data_direction == DMA_TO_DEVICE) { vfc_cmd->flags |= cpu_to_be16(IBMVFC_WRITE); - vfc_cmd->iu.add_cdb_len |= IBMVFC_WRDATA; + iu->add_cdb_len |= IBMVFC_WRDATA; } else { vfc_cmd->flags |= cpu_to_be16(IBMVFC_READ); - vfc_cmd->iu.add_cdb_len |= IBMVFC_RDDATA; + iu->add_cdb_len |= IBMVFC_RDDATA; } if (sg_mapped == 1) { @@ -1516,7 +1545,7 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt) { struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; + struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(vhost, vfc_cmd); struct scsi_cmnd *cmnd = evt->cmnd; const char *err = unknown_error; int index = ibmvfc_get_err_index(be16_to_cpu(vfc_cmd->status), be16_to_cpu(vfc_cmd->error)); @@ -1570,7 +1599,7 @@ static void ibmvfc_relogin(struct scsi_device *sdev) static void ibmvfc_scsi_done(struct ibmvfc_event *evt) { struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; - struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; + struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(evt->vhost, vfc_cmd); struct scsi_cmnd *cmnd = evt->cmnd; u32 rsp_len = 0; u32 sense_len = be32_to_cpu(rsp->fcp_sense_len); @@ -1584,7 +1613,7 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt) scsi_set_resid(cmnd, 0); if (vfc_cmd->status) { - cmnd->result = ibmvfc_get_err_result(vfc_cmd); + cmnd->result = ibmvfc_get_err_result(evt->vhost, vfc_cmd); if (rsp->flags & FCP_RSP_LEN_VALID) rsp_len = be32_to_cpu(rsp->fcp_rsp_len); @@ -1646,6 +1675,33 @@ static inline int ibmvfc_host_chkready(struct ibmvfc_host *vhost) return result; } +static struct ibmvfc_cmd *ibmvfc_init_vfc_cmd(struct ibmvfc_event *evt, struct scsi_device *sdev) +{ + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct ibmvfc_host *vhost = evt->vhost; + struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd; + struct ibmvfc_fcp_cmd_iu *iu = ibmvfc_get_fcp_iu(vhost, vfc_cmd); + struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(vhost, vfc_cmd); + size_t offset; + + memset(vfc_cmd, 0, sizeof(*vfc_cmd)); + if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) { + offset = offsetof(struct ibmvfc_cmd, v2.rsp); + vfc_cmd->target_wwpn = cpu_to_be64(rport->port_name); + } else + offset = offsetof(struct ibmvfc_cmd, v1.rsp); + vfc_cmd->resp.va = cpu_to_be64(be64_to_cpu(evt->crq.ioba) + offset); + vfc_cmd->resp.len = cpu_to_be32(sizeof(*rsp)); + vfc_cmd->frame_type = cpu_to_be32(IBMVFC_SCSI_FCP_TYPE); + vfc_cmd->payload_len = cpu_to_be32(sizeof(*iu)); + vfc_cmd->resp_len = cpu_to_be32(sizeof(*rsp)); + vfc_cmd->cancel_key = cpu_to_be32((unsigned long)sdev->hostdata); + vfc_cmd->tgt_scsi_id = cpu_to_be64(rport->port_id); + int_to_scsilun(sdev->lun, &iu->lun); + + return vfc_cmd; +} + /** * ibmvfc_queuecommand - The queuecommand function of the scsi template * @cmnd: struct scsi_cmnd to be executed @@ -1660,6 +1716,7 @@ static int ibmvfc_queuecommand_lck(struct scsi_cmnd *cmnd, struct ibmvfc_host *vhost = shost_priv(cmnd->device->host); struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); struct ibmvfc_cmd *vfc_cmd; + struct ibmvfc_fcp_cmd_iu *iu; struct ibmvfc_event *evt; int rc; @@ -1675,24 +1732,20 @@ static int ibmvfc_queuecommand_lck(struct scsi_cmnd *cmnd, ibmvfc_init_event(evt, ibmvfc_scsi_done, IBMVFC_CMD_FORMAT); evt->cmnd = cmnd; cmnd->scsi_done = done; - vfc_cmd = &evt->iu.cmd; - memset(vfc_cmd, 0, sizeof(*vfc_cmd)); - vfc_cmd->resp.va = cpu_to_be64(be64_to_cpu(evt->crq.ioba) + offsetof(struct ibmvfc_cmd, rsp)); - vfc_cmd->resp.len = cpu_to_be32(sizeof(vfc_cmd->rsp)); - vfc_cmd->frame_type = cpu_to_be32(IBMVFC_SCSI_FCP_TYPE); - vfc_cmd->payload_len = cpu_to_be32(sizeof(vfc_cmd->iu)); - vfc_cmd->resp_len = cpu_to_be32(sizeof(vfc_cmd->rsp)); - vfc_cmd->cancel_key = cpu_to_be32((unsigned long)cmnd->device->hostdata); - vfc_cmd->tgt_scsi_id = cpu_to_be64(rport->port_id); - vfc_cmd->iu.xfer_len = cpu_to_be32(scsi_bufflen(cmnd)); - int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun); - memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len); + + vfc_cmd = ibmvfc_init_vfc_cmd(evt, cmnd->device); + iu = ibmvfc_get_fcp_iu(vhost, vfc_cmd); + + iu->xfer_len = cpu_to_be32(scsi_bufflen(cmnd)); + memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len); if (cmnd->flags & SCMD_TAGGED) { vfc_cmd->task_tag = cpu_to_be64(cmnd->tag); - vfc_cmd->iu.pri_task_attr = IBMVFC_SIMPLE_TASK; + iu->pri_task_attr = IBMVFC_SIMPLE_TASK; } + vfc_cmd->correlation = cpu_to_be64(evt); + if (likely(!(rc = ibmvfc_map_sg_data(cmnd, evt, vfc_cmd, vhost->dev)))) return ibmvfc_send_event(evt, vhost, 0); @@ -2016,7 +2069,8 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) struct ibmvfc_cmd *tmf; struct ibmvfc_event *evt = NULL; union ibmvfc_iu rsp_iu; - struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; + struct ibmvfc_fcp_cmd_iu *iu; + struct ibmvfc_fcp_rsp *fc_rsp = ibmvfc_get_fcp_rsp(vhost, &rsp_iu.cmd); int rsp_rc = -EBUSY; unsigned long flags; int rsp_code = 0; @@ -2025,19 +2079,13 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) if (vhost->state == IBMVFC_ACTIVE) { evt = ibmvfc_get_event(vhost); ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); + tmf = ibmvfc_init_vfc_cmd(evt, sdev); + iu = ibmvfc_get_fcp_iu(vhost, tmf); - tmf = &evt->iu.cmd; - memset(tmf, 0, sizeof(*tmf)); - tmf->resp.va = cpu_to_be64(be64_to_cpu(evt->crq.ioba) + offsetof(struct ibmvfc_cmd, rsp)); - tmf->resp.len = cpu_to_be32(sizeof(tmf->rsp)); - tmf->frame_type = cpu_to_be32(IBMVFC_SCSI_FCP_TYPE); - tmf->payload_len = cpu_to_be32(sizeof(tmf->iu)); - tmf->resp_len = cpu_to_be32(sizeof(tmf->rsp)); - tmf->cancel_key = cpu_to_be32((unsigned long)sdev->hostdata); - tmf->tgt_scsi_id = cpu_to_be64(rport->port_id); - int_to_scsilun(sdev->lun, &tmf->iu.lun); tmf->flags = cpu_to_be16((IBMVFC_NO_MEM_DESC | IBMVFC_TMF)); - tmf->iu.tmf_flags = type; + if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) + tmf->target_wwpn = cpu_to_be64(rport->port_name); + iu->tmf_flags = type; evt->sync_iu = &rsp_iu; init_completion(&evt->comp); @@ -2055,7 +2103,7 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) wait_for_completion(&evt->comp); if (rsp_iu.cmd.status) - rsp_code = ibmvfc_get_err_result(&rsp_iu.cmd); + rsp_code = ibmvfc_get_err_result(vhost, &rsp_iu.cmd); if (rsp_code) { if (fc_rsp->flags & FCP_RSP_LEN_VALID) @@ -2227,12 +2275,17 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) tmf = &evt->iu.tmf; memset(tmf, 0, sizeof(*tmf)); - tmf->common.version = cpu_to_be32(1); + if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) { + tmf->common.version = cpu_to_be32(2); + tmf->target_wwpn = cpu_to_be64(rport->port_name); + } else { + tmf->common.version = cpu_to_be32(1); + } tmf->common.opcode = cpu_to_be32(IBMVFC_TMF_MAD); tmf->common.length = cpu_to_be16(sizeof(*tmf)); tmf->scsi_id = cpu_to_be64(rport->port_id); int_to_scsilun(sdev->lun, &tmf->lun); - if (!(be64_to_cpu(vhost->login_buf->resp.capabilities) & IBMVFC_CAN_SUPPRESS_ABTS)) + if (!ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPRESS_ABTS)) type &= ~IBMVFC_TMF_SUPPRESS_ABTS; if (vhost->state == IBMVFC_ACTIVE) tmf->flags = cpu_to_be32((type | IBMVFC_TMF_LUA_VALID)); @@ -2331,7 +2384,8 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev) struct ibmvfc_cmd *tmf; struct ibmvfc_event *evt, *found_evt; union ibmvfc_iu rsp_iu; - struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; + struct ibmvfc_fcp_cmd_iu *iu; + struct ibmvfc_fcp_rsp *fc_rsp = ibmvfc_get_fcp_rsp(vhost, &rsp_iu.cmd); int rc, rsp_rc = -EBUSY; unsigned long flags, timeout = IBMVFC_ABORT_TIMEOUT; int rsp_code = 0; @@ -2355,21 +2409,17 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev) if (vhost->state == IBMVFC_ACTIVE) { evt = ibmvfc_get_event(vhost); ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); + tmf = ibmvfc_init_vfc_cmd(evt, sdev); + iu = ibmvfc_get_fcp_iu(vhost, tmf); - tmf = &evt->iu.cmd; - memset(tmf, 0, sizeof(*tmf)); - tmf->resp.va = cpu_to_be64(be64_to_cpu(evt->crq.ioba) + offsetof(struct ibmvfc_cmd, rsp)); - tmf->resp.len = cpu_to_be32(sizeof(tmf->rsp)); - tmf->frame_type = cpu_to_be32(IBMVFC_SCSI_FCP_TYPE); - tmf->payload_len = cpu_to_be32(sizeof(tmf->iu)); - tmf->resp_len = cpu_to_be32(sizeof(tmf->rsp)); - tmf->cancel_key = cpu_to_be32((unsigned long)sdev->hostdata); - tmf->tgt_scsi_id = cpu_to_be64(rport->port_id); - int_to_scsilun(sdev->lun, &tmf->iu.lun); + if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) + tmf->target_wwpn = cpu_to_be64(rport->port_name); + iu->tmf_flags = IBMVFC_ABORT_TASK_SET; tmf->flags = cpu_to_be16((IBMVFC_NO_MEM_DESC | IBMVFC_TMF)); - tmf->iu.tmf_flags = IBMVFC_ABORT_TASK_SET; evt->sync_iu = &rsp_iu; + tmf->correlation = cpu_to_be64(evt); + init_completion(&evt->comp); rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); } @@ -2414,7 +2464,7 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev) } if (rsp_iu.cmd.status) - rsp_code = ibmvfc_get_err_result(&rsp_iu.cmd); + rsp_code = ibmvfc_get_err_result(vhost, &rsp_iu.cmd); if (rsp_code) { if (fc_rsp->flags & FCP_RSP_LEN_VALID) @@ -3025,7 +3075,7 @@ static ssize_t ibmvfc_show_host_npiv_version(struct device *dev, { struct Scsi_Host *shost = class_to_shost(dev); struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%d\n", vhost->login_buf->resp.version); + return snprintf(buf, PAGE_SIZE, "%d\n", be32_to_cpu(vhost->login_buf->resp.version)); } static ssize_t ibmvfc_show_host_capabilities(struct device *dev, @@ -3033,7 +3083,7 @@ static ssize_t ibmvfc_show_host_capabilities(struct device *dev, { struct Scsi_Host *shost = class_to_shost(dev); struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%llx\n", vhost->login_buf->resp.capabilities); + return snprintf(buf, PAGE_SIZE, "%llx\n", be64_to_cpu(vhost->login_buf->resp.capabilities)); } /** @@ -3445,7 +3495,12 @@ static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt) evt->tgt = tgt; prli = &evt->iu.prli; memset(prli, 0, sizeof(*prli)); - prli->common.version = cpu_to_be32(1); + if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) { + prli->common.version = cpu_to_be32(2); + prli->target_wwpn = cpu_to_be64(tgt->wwpn); + } else { + prli->common.version = cpu_to_be32(1); + } prli->common.opcode = cpu_to_be32(IBMVFC_PROCESS_LOGIN); prli->common.length = cpu_to_be16(sizeof(*prli)); prli->scsi_id = cpu_to_be64(tgt->scsi_id); @@ -3548,7 +3603,12 @@ static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt) evt->tgt = tgt; plogi = &evt->iu.plogi; memset(plogi, 0, sizeof(*plogi)); - plogi->common.version = cpu_to_be32(1); + if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) { + plogi->common.version = cpu_to_be32(2); + plogi->target_wwpn = cpu_to_be64(tgt->wwpn); + } else { + plogi->common.version = cpu_to_be32(1); + } plogi->common.opcode = cpu_to_be32(IBMVFC_PORT_LOGIN); plogi->common.length = cpu_to_be16(sizeof(*plogi)); plogi->scsi_id = cpu_to_be64(tgt->scsi_id); @@ -3948,7 +4008,12 @@ static void ibmvfc_adisc_timeout(struct timer_list *t) evt->tgt = tgt; tmf = &evt->iu.tmf; memset(tmf, 0, sizeof(*tmf)); - tmf->common.version = cpu_to_be32(1); + if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) { + tmf->common.version = cpu_to_be32(2); + tmf->target_wwpn = cpu_to_be64(tgt->wwpn); + } else { + tmf->common.version = cpu_to_be32(1); + } tmf->common.opcode = cpu_to_be32(IBMVFC_TMF_MAD); tmf->common.length = cpu_to_be16(sizeof(*tmf)); tmf->scsi_id = cpu_to_be64(tgt->scsi_id); @@ -4391,7 +4456,7 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *vhost) ibmvfc_dbg(vhost, "Sent NPIV login\n"); else ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); -}; +} /** * ibmvfc_npiv_logout_done - Completion handler for NPIV Logout diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 34debccfb142..9d58cfd774d3 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -54,6 +54,7 @@ #define IBMVFC_MAD_SUCCESS 0x00 #define IBMVFC_MAD_NOT_SUPPORTED 0xF1 +#define IBMVFC_MAD_VERSION_NOT_SUPP 0xF2 #define IBMVFC_MAD_FAILED 0xF7 #define IBMVFC_MAD_DRIVER_FAILED 0xEE #define IBMVFC_MAD_CRQ_ERROR 0xEF @@ -168,6 +169,8 @@ struct ibmvfc_npiv_login { #define IBMVFC_CAN_MIGRATE 0x01 #define IBMVFC_CAN_USE_CHANNELS 0x02 #define IBMVFC_CAN_HANDLE_FPIN 0x04 +#define IBMVFC_CAN_USE_MAD_VERSION 0x08 +#define IBMVFC_CAN_SEND_VF_WWPN 0x10 __be64 node_name; struct srp_direct_buf async; u8 partition_name[IBMVFC_MAX_NAME]; @@ -211,7 +214,9 @@ struct ibmvfc_npiv_login_resp { __be64 capabilities; #define IBMVFC_CAN_FLUSH_ON_HALT 0x08 #define IBMVFC_CAN_SUPPRESS_ABTS 0x10 -#define IBMVFC_CAN_SUPPORT_CHANNELS 0x20 +#define IBMVFC_MAD_VERSION_CAP 0x20 +#define IBMVFC_HANDLE_VF_WWPN 0x40 +#define IBMVFC_CAN_SUPPORT_CHANNELS 0x80 __be32 max_cmds; __be32 scsi_id_sz; __be64 max_dma_len; @@ -293,6 +298,7 @@ struct ibmvfc_port_login { __be32 reserved2; struct ibmvfc_service_parms service_parms; struct ibmvfc_service_parms service_parms_change; + __be64 target_wwpn; __be64 reserved3[2]; } __packed __aligned(8); @@ -344,6 +350,7 @@ struct ibmvfc_process_login { __be16 status; __be16 error; /* also fc_reason */ __be32 reserved2; + __be64 target_wwpn; __be64 reserved3[2]; } __packed __aligned(8); @@ -378,6 +385,8 @@ struct ibmvfc_tmf { __be32 cancel_key; __be32 my_cancel_key; __be32 pad; + __be64 target_wwpn; + __be64 task_tag; __be64 reserved[2]; } __packed __aligned(8); @@ -474,9 +483,19 @@ struct ibmvfc_cmd { __be64 correlation; __be64 tgt_scsi_id; __be64 tag; - __be64 reserved3[2]; - struct ibmvfc_fcp_cmd_iu iu; - struct ibmvfc_fcp_rsp rsp; + __be64 target_wwpn; + __be64 reserved3; + union { + struct { + struct ibmvfc_fcp_cmd_iu iu; + struct ibmvfc_fcp_rsp rsp; + } v1; + struct { + __be64 reserved4; + struct ibmvfc_fcp_cmd_iu iu; + struct ibmvfc_fcp_rsp rsp; + } v2; + }; } __packed __aligned(8); struct ibmvfc_passthru_fc_iu { @@ -503,6 +522,7 @@ struct ibmvfc_passthru_iu { __be64 correlation; __be64 scsi_id; __be64 tag; + __be64 target_wwpn; __be64 reserved2[2]; } __packed __aligned(8); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b0aa58d117cc..e451102b9a29 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -9487,7 +9487,6 @@ static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev, case pci_channel_io_perm_failure: ipr_pci_perm_failure(pdev); return PCI_ERS_RESULT_DISCONNECT; - break; default: break; } diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 93bc9019667f..c452849e7bb4 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -715,10 +715,6 @@ static int isci_suspend(struct device *dev) isci_host_deinit(ihost); } - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - return 0; } @@ -726,19 +722,7 @@ static int isci_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct isci_host *ihost; - int rc, i; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - rc = pcim_enable_device(pdev); - if (rc) { - dev_err(&pdev->dev, - "enabling device failure after resume(%d)\n", rc); - return rc; - } - - pci_set_master(pdev); + int i; for_each_isci_host(i, ihost, pdev) { sas_prep_resume_ha(&ihost->sas_ha); diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 7041e2e3ab48..1b87d9080ebe 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -753,7 +753,6 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) default: phy_event_warn(iphy, state, event_code); return SCI_FAILURE; - break; } return SCI_SUCCESS; case SCI_PHY_SUB_AWAIT_IAF_UF: @@ -958,7 +957,6 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) default: phy_event_warn(iphy, state, event_code); return SCI_FAILURE_INVALID_STATE; - break; } return SCI_SUCCESS; default: diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index df47557a02a3..a9ce6298b935 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -180,7 +180,7 @@ static void iscsi_sw_tcp_state_change(struct sock *sk) } /** - * iscsi_write_space - Called when more output buffer space is available + * iscsi_sw_tcp_write_space - Called when more output buffer space is available * @sk: socket space is available for **/ static void iscsi_sw_tcp_write_space(struct sock *sk) @@ -353,7 +353,7 @@ error: } /** - * iscsi_tcp_xmit_qlen - return the number of bytes queued for xmit + * iscsi_sw_tcp_xmit_qlen - return the number of bytes queued for xmit * @conn: iscsi connection */ static inline int iscsi_sw_tcp_xmit_qlen(struct iscsi_conn *conn) diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 13a2e7c33cb1..8d3006edbe12 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -15,7 +15,7 @@ #include <scsi/fc/fc_ns.h> #include <scsi/fc/fc_els.h> #include <scsi/libfc.h> -#include <scsi/fc_encode.h> +#include "fc_encode.h" #include "fc_libfc.h" /** diff --git a/drivers/scsi/libfc/fc_encode.h b/drivers/scsi/libfc/fc_encode.h new file mode 100644 index 000000000000..602c97a651bc --- /dev/null +++ b/drivers/scsi/libfc/fc_encode.h @@ -0,0 +1,707 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * Maintained at www.Open-FCoE.org + */ + +#ifndef _FC_ENCODE_H_ +#define _FC_ENCODE_H_ +#include <asm/unaligned.h> +#include <linux/utsname.h> +#include <scsi/fc/fc_ms.h> + +/* + * F_CTL values for simple requests and responses. + */ +#define FC_FCTL_REQ (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT) +#define FC_FCTL_RESP (FC_FC_EX_CTX | FC_FC_LAST_SEQ | \ + FC_FC_END_SEQ | FC_FC_SEQ_INIT) + +struct fc_ns_rft { + struct fc_ns_fid fid; /* port ID object */ + struct fc_ns_fts fts; /* FC4-types object */ +}; + +struct fc_ct_req { + struct fc_ct_hdr hdr; + union { + struct fc_ns_gid_ft gid; + struct fc_ns_rn_id rn; + struct fc_ns_rft rft; + struct fc_ns_rff_id rff; + struct fc_ns_fid fid; + struct fc_ns_rsnn snn; + struct fc_ns_rspn spn; + struct fc_fdmi_rhba rhba; + struct fc_fdmi_rpa rpa; + struct fc_fdmi_dprt dprt; + struct fc_fdmi_dhba dhba; + } payload; +}; + +/** + * fc_adisc_fill() - Fill in adisc request frame + * @lport: local port. + * @fp: fc frame where payload will be placed. + */ +static inline void fc_adisc_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_els_adisc *adisc; + + adisc = fc_frame_payload_get(fp, sizeof(*adisc)); + memset(adisc, 0, sizeof(*adisc)); + adisc->adisc_cmd = ELS_ADISC; + put_unaligned_be64(lport->wwpn, &adisc->adisc_wwpn); + put_unaligned_be64(lport->wwnn, &adisc->adisc_wwnn); + hton24(adisc->adisc_port_id, lport->port_id); +} + +/** + * fc_ct_hdr_fill- fills ct header and reset ct payload + * returns pointer to ct request. + */ +static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp, + unsigned int op, size_t req_size, + enum fc_ct_fs_type fs_type, + u8 subtype) +{ + struct fc_ct_req *ct; + size_t ct_plen; + + ct_plen = sizeof(struct fc_ct_hdr) + req_size; + ct = fc_frame_payload_get(fp, ct_plen); + memset(ct, 0, ct_plen); + ct->hdr.ct_rev = FC_CT_REV; + ct->hdr.ct_fs_type = fs_type; + ct->hdr.ct_fs_subtype = subtype; + ct->hdr.ct_cmd = htons((u16) op); + return ct; +} + +/** + * fc_ct_ns_fill() - Fill in a name service request frame + * @lport: local port. + * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries. + * @fp: frame to contain payload. + * @op: CT opcode. + * @r_ctl: pointer to FC header R_CTL. + * @fh_type: pointer to FC-4 type. + */ +static inline int fc_ct_ns_fill(struct fc_lport *lport, + u32 fc_id, struct fc_frame *fp, + unsigned int op, enum fc_rctl *r_ctl, + enum fc_fh_type *fh_type) +{ + struct fc_ct_req *ct; + size_t len; + + switch (op) { + case FC_NS_GPN_FT: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_gid_ft), + FC_FST_DIR, FC_NS_SUBTYPE); + ct->payload.gid.fn_fc4_type = FC_TYPE_FCP; + break; + + case FC_NS_GPN_ID: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_fid), + FC_FST_DIR, FC_NS_SUBTYPE); + ct->payload.gid.fn_fc4_type = FC_TYPE_FCP; + hton24(ct->payload.fid.fp_fid, fc_id); + break; + + case FC_NS_RFT_ID: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft), + FC_FST_DIR, FC_NS_SUBTYPE); + hton24(ct->payload.rft.fid.fp_fid, lport->port_id); + ct->payload.rft.fts = lport->fcts; + break; + + case FC_NS_RFF_ID: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rff_id), + FC_FST_DIR, FC_NS_SUBTYPE); + hton24(ct->payload.rff.fr_fid.fp_fid, lport->port_id); + ct->payload.rff.fr_type = FC_TYPE_FCP; + if (lport->service_params & FCP_SPPF_INIT_FCN) + ct->payload.rff.fr_feat = FCP_FEAT_INIT; + if (lport->service_params & FCP_SPPF_TARG_FCN) + ct->payload.rff.fr_feat |= FCP_FEAT_TARG; + break; + + case FC_NS_RNN_ID: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id), + FC_FST_DIR, FC_NS_SUBTYPE); + hton24(ct->payload.rn.fr_fid.fp_fid, lport->port_id); + put_unaligned_be64(lport->wwnn, &ct->payload.rn.fr_wwn); + break; + + case FC_NS_RSPN_ID: + len = strnlen(fc_host_symbolic_name(lport->host), 255); + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len, + FC_FST_DIR, FC_NS_SUBTYPE); + hton24(ct->payload.spn.fr_fid.fp_fid, lport->port_id); + strncpy(ct->payload.spn.fr_name, + fc_host_symbolic_name(lport->host), len); + ct->payload.spn.fr_name_len = len; + break; + + case FC_NS_RSNN_NN: + len = strnlen(fc_host_symbolic_name(lport->host), 255); + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rsnn) + len, + FC_FST_DIR, FC_NS_SUBTYPE); + put_unaligned_be64(lport->wwnn, &ct->payload.snn.fr_wwn); + strncpy(ct->payload.snn.fr_name, + fc_host_symbolic_name(lport->host), len); + ct->payload.snn.fr_name_len = len; + break; + + default: + return -EINVAL; + } + *r_ctl = FC_RCTL_DD_UNSOL_CTL; + *fh_type = FC_TYPE_CT; + return 0; +} + +static inline void fc_ct_ms_fill_attr(struct fc_fdmi_attr_entry *entry, + const char *in, size_t len) +{ + int copied = strscpy(entry->value, in, len); + if (copied > 0) + memset(entry->value, copied, len - copied); +} + +/** + * fc_ct_ms_fill() - Fill in a mgmt service request frame + * @lport: local port. + * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries. + * @fp: frame to contain payload. + * @op: CT opcode. + * @r_ctl: pointer to FC header R_CTL. + * @fh_type: pointer to FC-4 type. + */ +static inline int fc_ct_ms_fill(struct fc_lport *lport, + u32 fc_id, struct fc_frame *fp, + unsigned int op, enum fc_rctl *r_ctl, + enum fc_fh_type *fh_type) +{ + struct fc_ct_req *ct; + size_t len; + struct fc_fdmi_attr_entry *entry; + struct fs_fdmi_attrs *hba_attrs; + int numattrs = 0; + + switch (op) { + case FC_FDMI_RHBA: + numattrs = 10; + len = sizeof(struct fc_fdmi_rhba); + len -= sizeof(struct fc_fdmi_attr_entry); + len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); + len += FC_FDMI_HBA_ATTR_NODENAME_LEN; + len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN; + len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN; + len += FC_FDMI_HBA_ATTR_MODEL_LEN; + len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN; + len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN; + len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN; + len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN; + len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN; + len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN; + ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT, + FC_FDMI_SUBTYPE); + + /* HBA Identifier */ + put_unaligned_be64(lport->wwpn, &ct->payload.rhba.hbaid.id); + /* Number of Ports - always 1 */ + put_unaligned_be32(1, &ct->payload.rhba.port.numport); + /* Port Name */ + put_unaligned_be64(lport->wwpn, + &ct->payload.rhba.port.port[0].portname); + + /* HBA Attributes */ + put_unaligned_be32(numattrs, + &ct->payload.rhba.hba_attrs.numattrs); + hba_attrs = &ct->payload.rhba.hba_attrs; + entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr; + /* NodeName*/ + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_NODENAME_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_NODENAME, + &entry->type); + put_unaligned_be16(len, &entry->len); + put_unaligned_be64(lport->wwnn, + (__be64 *)&entry->value[0]); + + /* Manufacturer */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_NODENAME_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_MANUFACTURER, + &entry->type); + put_unaligned_be16(len, &entry->len); + fc_ct_ms_fill_attr(entry, + fc_host_manufacturer(lport->host), + FC_FDMI_HBA_ATTR_MANUFACTURER_LEN); + + /* SerialNumber */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_MANUFACTURER_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_SERIALNUMBER, + &entry->type); + put_unaligned_be16(len, &entry->len); + fc_ct_ms_fill_attr(entry, + fc_host_serial_number(lport->host), + FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN); + + /* Model */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_MODEL_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_MODEL, + &entry->type); + put_unaligned_be16(len, &entry->len); + fc_ct_ms_fill_attr(entry, + fc_host_model(lport->host), + FC_FDMI_HBA_ATTR_MODEL_LEN); + + /* Model Description */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_MODEL_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_MODELDESCRIPTION, + &entry->type); + put_unaligned_be16(len, &entry->len); + fc_ct_ms_fill_attr(entry, + fc_host_model_description(lport->host), + FC_FDMI_HBA_ATTR_MODELDESCR_LEN); + + /* Hardware Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_MODELDESCR_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_HARDWAREVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + fc_ct_ms_fill_attr(entry, + fc_host_hardware_version(lport->host), + FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN); + + /* Driver Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_DRIVERVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + fc_ct_ms_fill_attr(entry, + fc_host_driver_version(lport->host), + FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN); + + /* OptionROM Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_OPTIONROMVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + fc_ct_ms_fill_attr(entry, + fc_host_optionrom_version(lport->host), + FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN); + + /* Firmware Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_FIRMWAREVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + fc_ct_ms_fill_attr(entry, + fc_host_firmware_version(lport->host), + FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN); + + /* OS Name and Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_OSNAMEVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + snprintf((char *)&entry->value, + FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN, + "%s v%s", + init_utsname()->sysname, + init_utsname()->release); + break; + case FC_FDMI_RPA: + numattrs = 6; + len = sizeof(struct fc_fdmi_rpa); + len -= sizeof(struct fc_fdmi_attr_entry); + len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); + len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN; + len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN; + len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN; + len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN; + len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN; + len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN; + ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT, + FC_FDMI_SUBTYPE); + + /* Port Name */ + put_unaligned_be64(lport->wwpn, + &ct->payload.rpa.port.portname); + + /* Port Attributes */ + put_unaligned_be32(numattrs, + &ct->payload.rpa.hba_attrs.numattrs); + + hba_attrs = &ct->payload.rpa.hba_attrs; + entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr; + + /* FC4 types */ + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_FC4TYPES, + &entry->type); + put_unaligned_be16(len, &entry->len); + memcpy(&entry->value, fc_host_supported_fc4s(lport->host), + FC_FDMI_PORT_ATTR_FC4TYPES_LEN); + + /* Supported Speed */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_FC4TYPES_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_SUPPORTEDSPEED, + &entry->type); + put_unaligned_be16(len, &entry->len); + + put_unaligned_be32(fc_host_supported_speeds(lport->host), + &entry->value); + + /* Current Port Speed */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_CURRENTPORTSPEED, + &entry->type); + put_unaligned_be16(len, &entry->len); + put_unaligned_be32(lport->link_speed, + &entry->value); + + /* Max Frame Size */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_MAXFRAMESIZE, + &entry->type); + put_unaligned_be16(len, &entry->len); + put_unaligned_be32(fc_host_maxframe_size(lport->host), + &entry->value); + + /* OS Device Name */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_OSDEVICENAME, + &entry->type); + put_unaligned_be16(len, &entry->len); + /* Use the sysfs device name */ + fc_ct_ms_fill_attr(entry, + dev_name(&lport->host->shost_gendev), + strnlen(dev_name(&lport->host->shost_gendev), + FC_FDMI_PORT_ATTR_HOSTNAME_LEN)); + + /* Host Name */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_HOSTNAME, + &entry->type); + put_unaligned_be16(len, &entry->len); + if (strlen(fc_host_system_hostname(lport->host))) + fc_ct_ms_fill_attr(entry, + fc_host_system_hostname(lport->host), + strnlen(fc_host_system_hostname(lport->host), + FC_FDMI_PORT_ATTR_HOSTNAME_LEN)); + else + fc_ct_ms_fill_attr(entry, + init_utsname()->nodename, + FC_FDMI_PORT_ATTR_HOSTNAME_LEN); + break; + case FC_FDMI_DPRT: + len = sizeof(struct fc_fdmi_dprt); + ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT, + FC_FDMI_SUBTYPE); + /* Port Name */ + put_unaligned_be64(lport->wwpn, + &ct->payload.dprt.port.portname); + break; + case FC_FDMI_DHBA: + len = sizeof(struct fc_fdmi_dhba); + ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT, + FC_FDMI_SUBTYPE); + /* HBA Identifier */ + put_unaligned_be64(lport->wwpn, &ct->payload.dhba.hbaid.id); + break; + default: + return -EINVAL; + } + *r_ctl = FC_RCTL_DD_UNSOL_CTL; + *fh_type = FC_TYPE_CT; + return 0; +} + +/** + * fc_ct_fill() - Fill in a common transport service request frame + * @lport: local port. + * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries. + * @fp: frame to contain payload. + * @op: CT opcode. + * @r_ctl: pointer to FC header R_CTL. + * @fh_type: pointer to FC-4 type. + */ +static inline int fc_ct_fill(struct fc_lport *lport, + u32 fc_id, struct fc_frame *fp, + unsigned int op, enum fc_rctl *r_ctl, + enum fc_fh_type *fh_type, u32 *did) +{ + int rc = -EINVAL; + + switch (fc_id) { + case FC_FID_MGMT_SERV: + rc = fc_ct_ms_fill(lport, fc_id, fp, op, r_ctl, fh_type); + *did = FC_FID_MGMT_SERV; + break; + case FC_FID_DIR_SERV: + default: + rc = fc_ct_ns_fill(lport, fc_id, fp, op, r_ctl, fh_type); + *did = FC_FID_DIR_SERV; + break; + } + + return rc; +} +/** + * fc_plogi_fill - Fill in plogi request frame + */ +static inline void fc_plogi_fill(struct fc_lport *lport, struct fc_frame *fp, + unsigned int op) +{ + struct fc_els_flogi *plogi; + struct fc_els_csp *csp; + struct fc_els_cssp *cp; + + plogi = fc_frame_payload_get(fp, sizeof(*plogi)); + memset(plogi, 0, sizeof(*plogi)); + plogi->fl_cmd = (u8) op; + put_unaligned_be64(lport->wwpn, &plogi->fl_wwpn); + put_unaligned_be64(lport->wwnn, &plogi->fl_wwnn); + + csp = &plogi->fl_csp; + csp->sp_hi_ver = 0x20; + csp->sp_lo_ver = 0x20; + csp->sp_bb_cred = htons(10); /* this gets set by gateway */ + csp->sp_bb_data = htons((u16) lport->mfs); + cp = &plogi->fl_cssp[3 - 1]; /* class 3 parameters */ + cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); + csp->sp_features = htons(FC_SP_FT_CIRO); + csp->sp_tot_seq = htons(255); /* seq. we accept */ + csp->sp_rel_off = htons(0x1f); + csp->sp_e_d_tov = htonl(lport->e_d_tov); + + cp->cp_rdfs = htons((u16) lport->mfs); + cp->cp_con_seq = htons(255); + cp->cp_open_seq = 1; +} + +/** + * fc_flogi_fill - Fill in a flogi request frame. + */ +static inline void fc_flogi_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_els_csp *sp; + struct fc_els_cssp *cp; + struct fc_els_flogi *flogi; + + flogi = fc_frame_payload_get(fp, sizeof(*flogi)); + memset(flogi, 0, sizeof(*flogi)); + flogi->fl_cmd = (u8) ELS_FLOGI; + put_unaligned_be64(lport->wwpn, &flogi->fl_wwpn); + put_unaligned_be64(lport->wwnn, &flogi->fl_wwnn); + sp = &flogi->fl_csp; + sp->sp_hi_ver = 0x20; + sp->sp_lo_ver = 0x20; + sp->sp_bb_cred = htons(10); /* this gets set by gateway */ + sp->sp_bb_data = htons((u16) lport->mfs); + cp = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */ + cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); + if (lport->does_npiv) + sp->sp_features = htons(FC_SP_FT_NPIV); +} + +/** + * fc_fdisc_fill - Fill in a fdisc request frame. + */ +static inline void fc_fdisc_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_els_csp *sp; + struct fc_els_cssp *cp; + struct fc_els_flogi *fdisc; + + fdisc = fc_frame_payload_get(fp, sizeof(*fdisc)); + memset(fdisc, 0, sizeof(*fdisc)); + fdisc->fl_cmd = (u8) ELS_FDISC; + put_unaligned_be64(lport->wwpn, &fdisc->fl_wwpn); + put_unaligned_be64(lport->wwnn, &fdisc->fl_wwnn); + sp = &fdisc->fl_csp; + sp->sp_hi_ver = 0x20; + sp->sp_lo_ver = 0x20; + sp->sp_bb_cred = htons(10); /* this gets set by gateway */ + sp->sp_bb_data = htons((u16) lport->mfs); + cp = &fdisc->fl_cssp[3 - 1]; /* class 3 parameters */ + cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); +} + +/** + * fc_logo_fill - Fill in a logo request frame. + */ +static inline void fc_logo_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_els_logo *logo; + + logo = fc_frame_payload_get(fp, sizeof(*logo)); + memset(logo, 0, sizeof(*logo)); + logo->fl_cmd = ELS_LOGO; + hton24(logo->fl_n_port_id, lport->port_id); + logo->fl_n_port_wwn = htonll(lport->wwpn); +} + +/** + * fc_rtv_fill - Fill in RTV (read timeout value) request frame. + */ +static inline void fc_rtv_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_els_rtv *rtv; + + rtv = fc_frame_payload_get(fp, sizeof(*rtv)); + memset(rtv, 0, sizeof(*rtv)); + rtv->rtv_cmd = ELS_RTV; +} + +/** + * fc_rec_fill - Fill in rec request frame + */ +static inline void fc_rec_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_els_rec *rec; + struct fc_exch *ep = fc_seq_exch(fr_seq(fp)); + + rec = fc_frame_payload_get(fp, sizeof(*rec)); + memset(rec, 0, sizeof(*rec)); + rec->rec_cmd = ELS_REC; + hton24(rec->rec_s_id, lport->port_id); + rec->rec_ox_id = htons(ep->oxid); + rec->rec_rx_id = htons(ep->rxid); +} + +/** + * fc_prli_fill - Fill in prli request frame + */ +static inline void fc_prli_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct { + struct fc_els_prli prli; + struct fc_els_spp spp; + } *pp; + + pp = fc_frame_payload_get(fp, sizeof(*pp)); + memset(pp, 0, sizeof(*pp)); + pp->prli.prli_cmd = ELS_PRLI; + pp->prli.prli_spp_len = sizeof(struct fc_els_spp); + pp->prli.prli_len = htons(sizeof(*pp)); + pp->spp.spp_type = FC_TYPE_FCP; + pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR; + pp->spp.spp_params = htonl(lport->service_params); +} + +/** + * fc_scr_fill - Fill in a scr request frame. + */ +static inline void fc_scr_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_els_scr *scr; + + scr = fc_frame_payload_get(fp, sizeof(*scr)); + memset(scr, 0, sizeof(*scr)); + scr->scr_cmd = ELS_SCR; + scr->scr_reg_func = ELS_SCRF_FULL; +} + +/** + * fc_els_fill - Fill in an ELS request frame + */ +static inline int fc_els_fill(struct fc_lport *lport, + u32 did, + struct fc_frame *fp, unsigned int op, + enum fc_rctl *r_ctl, enum fc_fh_type *fh_type) +{ + switch (op) { + case ELS_ADISC: + fc_adisc_fill(lport, fp); + break; + + case ELS_PLOGI: + fc_plogi_fill(lport, fp, ELS_PLOGI); + break; + + case ELS_FLOGI: + fc_flogi_fill(lport, fp); + break; + + case ELS_FDISC: + fc_fdisc_fill(lport, fp); + break; + + case ELS_LOGO: + fc_logo_fill(lport, fp); + break; + + case ELS_RTV: + fc_rtv_fill(lport, fp); + break; + + case ELS_REC: + fc_rec_fill(lport, fp); + break; + + case ELS_PRLI: + fc_prli_fill(lport, fp); + break; + + case ELS_SCR: + fc_scr_fill(lport, fp); + break; + + default: + return -EINVAL; + } + + *r_ctl = FC_RCTL_ELS_REQ; + *fh_type = FC_TYPE_ELS; + return 0; +} +#endif /* _FC_ENCODE_H_ */ diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 96a2952cf626..d71afae6191c 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -20,7 +20,6 @@ #include <scsi/fc/fc_fc2.h> #include <scsi/libfc.h> -#include <scsi/fc_encode.h> #include "fc_libfc.h" @@ -272,7 +271,7 @@ static void fc_exch_setup_hdr(struct fc_exch *ep, struct fc_frame *fp, if (f_ctl & FC_FC_END_SEQ) { fr_eof(fp) = FC_EOF_T; - if (fc_sof_needs_ack(ep->class)) + if (fc_sof_needs_ack((enum fc_sof)ep->class)) fr_eof(fp) = FC_EOF_N; /* * From F_CTL. diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 7cfeb6886237..b43b5f62ee3e 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -26,8 +26,8 @@ #include <scsi/fc/fc_fc2.h> #include <scsi/libfc.h> -#include <scsi/fc_encode.h> +#include "fc_encode.h" #include "fc_libfc.h" static struct kmem_cache *scsi_pkt_cachep; diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index 19c4ab4e0f4d..0e6a1355d020 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c @@ -12,8 +12,8 @@ #include <linux/module.h> #include <scsi/libfc.h> -#include <scsi/fc_encode.h> +#include "fc_encode.h" #include "fc_libfc.h" MODULE_AUTHOR("Open-FCoE.org"); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 6557fda85c5c..22826544da7e 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -84,9 +84,9 @@ #include <scsi/fc/fc_gs.h> #include <scsi/libfc.h> -#include <scsi/fc_encode.h> #include <linux/scatterlist.h> +#include "fc_encode.h" #include "fc_libfc.h" /* Fabric IDs to use for point-to-point mode, chosen on whims. */ diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index a60b228d13f1..56003208d2e7 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -58,8 +58,8 @@ #include <asm/unaligned.h> #include <scsi/libfc.h> -#include <scsi/fc_encode.h> +#include "fc_encode.h" #include "fc_libfc.h" static struct workqueue_struct *rport_event_queue; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index f9314f1393fb..4e668aafbcca 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -780,7 +780,7 @@ int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); /** - * iscsi_cmd_rsp - SCSI Command Response processing + * iscsi_scsi_cmd_rsp - SCSI Command Response processing * @conn: iscsi connection * @hdr: iscsi header * @task: scsi command task diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 549adfaa97ce..a54c8da30273 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -664,11 +664,18 @@ struct lpfc_hba { void (*lpfc_scsi_prep_cmnd) (struct lpfc_vport *, struct lpfc_io_buf *, struct lpfc_nodelist *); + int (*lpfc_scsi_prep_cmnd_buf) + (struct lpfc_vport *vport, + struct lpfc_io_buf *lpfc_cmd, + uint8_t tmo); /* IOCB interface function jump table entries */ int (*__lpfc_sli_issue_iocb) (struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, uint32_t); + int (*__lpfc_sli_issue_fcp_io) + (struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag); void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *, struct lpfc_iocbq *); int (*lpfc_hba_down_post)(struct lpfc_hba *phba); @@ -744,7 +751,8 @@ struct lpfc_hba { #define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ #define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */ #define LS_MDS_LINK_DOWN 0x8 /* MDS Diagnostics Link Down */ -#define LS_MDS_LOOPBACK 0x10 /* MDS Diagnostics Link Up (Loopback) */ +#define LS_MDS_LOOPBACK 0x10 /* MDS Diagnostics Link Up (Loopback) */ +#define LS_CT_VEN_RPA 0x20 /* Vendor RPA sent to switch */ uint32_t hba_flag; /* hba generic flags */ #define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */ @@ -753,7 +761,7 @@ struct lpfc_hba { #define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/ #define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */ #define HBA_PERSISTENT_TOPO 0x20 /* Persistent topology support in hba */ -#define ELS_XRI_ABORT_EVENT 0x40 +#define ELS_XRI_ABORT_EVENT 0x40 /* ELS_XRI abort event was queued */ #define ASYNC_EVENT 0x80 #define LINK_DISABLED 0x100 /* Link disabled by user */ #define FCF_TS_INPROG 0x200 /* FCF table scan in progress */ @@ -922,6 +930,7 @@ struct lpfc_hba { #define LPFC_ENABLE_NVME 2 #define LPFC_ENABLE_BOTH 3 uint32_t cfg_enable_pbde; + uint32_t cfg_enable_mi; struct nvmet_fc_target_port *targetport; lpfc_vpd_t vpd; /* vital product data */ @@ -1129,8 +1138,6 @@ struct lpfc_hba { uint8_t hb_outstanding; struct timer_list rrq_tmr; enum hba_temp_state over_temp_state; - /* ndlp reference management */ - spinlock_t ndlp_lock; /* * Following bit will be set for all buffer tags which are not * associated with any HBQ. diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e94eac194676..4528166dee36 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -57,10 +57,6 @@ #define LPFC_MIN_DEVLOSS_TMO 1 #define LPFC_MAX_DEVLOSS_TMO 255 -#define LPFC_DEF_MRQ_POST 512 -#define LPFC_MIN_MRQ_POST 512 -#define LPFC_MAX_MRQ_POST 2048 - /* * Write key size should be multiple of 4. If write key is changed * make sure that library write key is also changed. @@ -372,11 +368,11 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { nrport = NULL; - spin_lock(&vport->phba->hbalock); + spin_lock(&ndlp->lock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) nrport = rport->remoteport; - spin_unlock(&vport->phba->hbalock); + spin_unlock(&ndlp->lock); if (!nrport) continue; @@ -1505,6 +1501,7 @@ lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) /** * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc * @phba: lpfc_hba pointer. + * @opcode: The sli4 config command opcode. * * Description: * Request SLI4 interface type-2 device to perform a physical register set @@ -2288,7 +2285,7 @@ lpfc_enable_bbcr_set(struct lpfc_hba *phba, uint val) return -EINVAL; } -/** +/* * lpfc_param_show - Return a cfg attribute value in decimal * * Description: @@ -2314,7 +2311,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ phba->cfg_##attr);\ } -/** +/* * lpfc_param_hex_show - Return a cfg attribute value in hex * * Description: @@ -2342,7 +2339,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ phba->cfg_##attr);\ } -/** +/* * lpfc_param_init - Initializes a cfg attribute * * Description: @@ -2376,7 +2373,7 @@ lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \ return -EINVAL;\ } -/** +/* * lpfc_param_set - Set a cfg attribute value * * Description: @@ -2413,7 +2410,7 @@ lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \ return -EINVAL;\ } -/** +/* * lpfc_param_store - Set a vport attribute value * * Description: @@ -2453,7 +2450,7 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \ return -EINVAL;\ } -/** +/* * lpfc_vport_param_show - Return decimal formatted cfg attribute value * * Description: @@ -2477,7 +2474,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ return scnprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\ } -/** +/* * lpfc_vport_param_hex_show - Return hex formatted attribute value * * Description: @@ -2502,7 +2499,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ return scnprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\ } -/** +/* * lpfc_vport_param_init - Initialize a vport cfg attribute * * Description: @@ -2535,7 +2532,7 @@ lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \ return -EINVAL;\ } -/** +/* * lpfc_vport_param_set - Set a vport cfg attribute * * Description: @@ -2571,7 +2568,7 @@ lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \ return -EINVAL;\ } -/** +/* * lpfc_vport_param_store - Set a vport attribute * * Description: @@ -2774,7 +2771,7 @@ lpfc_soft_wwpn_show(struct device *dev, struct device_attribute *attr, /** * lpfc_soft_wwpn_store - Set the ww port name of the adapter - * @dev class device that is converted into a Scsi_host. + * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. * @buf: contains the wwpn in hexadecimal. * @count: number of wwpn bytes in buf @@ -2871,7 +2868,8 @@ lpfc_soft_wwnn_show(struct device *dev, struct device_attribute *attr, /** * lpfc_soft_wwnn_store - sets the ww node name of the adapter - * @cdev: class device that is converted into a Scsi_host. + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. * @buf: contains the ww node name in hexadecimal. * @count: number of wwnn bytes in buf. * @@ -3207,9 +3205,11 @@ static DEVICE_ATTR(lpfc_xlane_lun_status, S_IRUGO, * lpfc_oas_lun_state_set - enable or disable a lun for Optimized Access Storage * (OAS) operations. * @phba: lpfc_hba pointer. - * @ndlp: pointer to fcp target node. + * @vpt_wwpn: wwpn of the vport associated with the returned lun + * @tgt_wwpn: wwpn of the target associated with the returned lun * @lun: the fc lun for setting oas state. * @oas_state: the oas state to be set to the lun. + * @pri: priority * * Returns: * SUCCESS : 0 @@ -3247,6 +3247,7 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], * @vpt_wwpn: wwpn of the vport associated with the returned lun * @tgt_wwpn: wwpn of the target associated with the returned lun * @lun_status: status of the lun returned lun + * @lun_pri: priority of the lun returned lun * * Returns the first or next lun enabled for OAS operations for the vport/target * specified. If a lun is found, its vport wwpn, target wwpn and status is @@ -3285,6 +3286,7 @@ lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[], * @tgt_wwpn: target wwpn by reference. * @lun: the fc lun for setting oas state. * @oas_state: the oas state to be set to the oas_lun. + * @pri: priority * * This routine enables (OAS_LUN_ENABLE) or disables (OAS_LUN_DISABLE) * a lun for OAS operations. @@ -3359,6 +3361,7 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr, * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. * @buf: buffer for passing information. + * @count: size of the formatting string * * This function sets the OAS state for lun. Before this function is called, * the vport wwpn, target wwpn, and oas state need to be set. @@ -3631,16 +3634,14 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) shost = lpfc_shost_from_vport(vport); spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->rport) ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; #if (IS_ENABLED(CONFIG_NVME_FC)) - spin_lock(&vport->phba->hbalock); + spin_lock(&ndlp->lock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) remoteport = rport->remoteport; - spin_unlock(&vport->phba->hbalock); + spin_unlock(&ndlp->lock); if (rport && remoteport) nvme_fc_set_remoteport_devloss(remoteport, vport->cfg_devloss_tmo); @@ -3820,7 +3821,7 @@ lpfc_vport_param_init(tgt_queue_depth, LPFC_MAX_TGT_QDEPTH, /** * lpfc_tgt_queue_depth_store: Sets an attribute value. - * @phba: pointer the the adapter structure. + * @vport: lpfc vport structure pointer. * @val: integer attribute value. * * Description: Sets the parameter to the new value. @@ -4005,8 +4006,10 @@ LPFC_ATTR(topology, 0, 0, 6, /** * lpfc_topology_set - Set the adapters topology field - * @phba: lpfc_hba pointer. - * @val: topology value. + * @dev: class device that is converted into a scsi_host. + * @attr:device attribute, not used. + * @buf: buffer for passing information. + * @count: size of the data buffer. * * Description: * If val is in a valid range then set the adapter's topology field and @@ -4125,6 +4128,7 @@ static DEVICE_ATTR_RO(lpfc_static_vport); /** * lpfc_stat_data_ctrl_store - write call back for lpfc_stat_data_ctrl sysfs file * @dev: Pointer to class device. + * @attr: Unused. * @buf: Data buffer. * @count: Size of the data buffer. * @@ -4288,7 +4292,8 @@ lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr, /** * lpfc_stat_data_ctrl_show - Read function for lpfc_stat_data_ctrl sysfs file - * @dev: Pointer to class device object. + * @dev: Pointer to class device. + * @attr: Unused. * @buf: Data buffer. * * This function is the read call back function for @@ -4367,7 +4372,7 @@ static DEVICE_ATTR_RW(lpfc_stat_data_ctrl); * @filp: sysfs file * @kobj: Pointer to the kernel object * @bin_attr: Attribute object - * @buff: Buffer pointer + * @buf: Buffer pointer * @off: File offset * @count: Buffer size * @@ -4397,7 +4402,7 @@ sysfs_drvr_stat_data_read(struct file *filp, struct kobject *kobj, spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp) || !ndlp->lat_data) + if (!ndlp->lat_data) continue; if (nport_index > 0) { @@ -4454,8 +4459,10 @@ static struct bin_attribute sysfs_drvr_stat_data_attr = { */ /** * lpfc_link_speed_set - Set the adapters link speed - * @phba: lpfc_hba pointer. - * @val: link speed value. + * @dev: Pointer to class device. + * @attr: Unused. + * @buf: Data buffer. + * @count: Size of the data buffer. * * Description: * If val is in a valid range then set the adapter's link speed field and @@ -5463,8 +5470,6 @@ lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val) spin_lock_irq(shost->host_lock); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; @@ -6138,6 +6143,14 @@ LPFC_BBCR_ATTR_RW(enable_bbcr, 1, 0, 1, "Enable BBC Recovery"); */ LPFC_ATTR_RW(enable_dpp, 1, 0, 1, "Enable Direct Packet Push"); +/* + * lpfc_enable_mi: Enable FDMI MIB + * 0 = disabled + * 1 = enabled (default) + * Value range is [0,1]. + */ +LPFC_ATTR_R(enable_mi, 1, 0, 1, "Enable MI"); + struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_nvme_info, &dev_attr_scsi_stat, @@ -6255,6 +6268,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_ras_fwlog_func, &dev_attr_lpfc_enable_bbcr, &dev_attr_lpfc_enable_dpp, + &dev_attr_lpfc_enable_mi, NULL, }; @@ -6964,8 +6978,7 @@ lpfc_get_node_by_target(struct scsi_target *starget) spin_lock_irq(shost->host_lock); /* Search for this, mapped, target ID */ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_MAPPED_NODE && + if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && starget->id == ndlp->nlp_sid) { spin_unlock_irq(shost->host_lock); return ndlp; @@ -7040,7 +7053,7 @@ lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) else rport->dev_loss_tmo = 1; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { dev_info(&rport->dev, "Cannot find remote node to " "set rport dev loss tmo, port_id x%x\n", rport->port_id); @@ -7056,7 +7069,7 @@ lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) #endif } -/** +/* * lpfc_rport_show_function - Return rport target information * * Description: @@ -7105,6 +7118,7 @@ lpfc_set_vport_symbolic_name(struct fc_vport *fc_vport) /** * lpfc_hba_log_verbose_init - Set hba's log verbose level * @phba: Pointer to lpfc_hba struct. + * @verbose: Verbose level to set. * * This function is called by the lpfc_get_cfgparam() routine to set the * module lpfc_log_verbose into the @phba cfg_log_verbose for use with @@ -7359,6 +7373,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_irq_chann_init(phba, lpfc_irq_chann); lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr); lpfc_enable_dpp_init(phba, lpfc_enable_dpp); + lpfc_enable_mi_init(phba, lpfc_enable_mi); if (phba->sli_rev != LPFC_SLI_REV4) { /* NVME only supported on SLI4 */ diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 6f9d648a9b9c..eed6ea5e0722 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -329,7 +329,7 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, spin_unlock_irqrestore(&phba->hbalock, flags); iocb = &dd_data->context_un.iocb; - ndlp = iocb->ndlp; + ndlp = iocb->cmdiocbq->context_un.ndlp; rmp = iocb->rmp; cmp = cmdiocbq->context2; bmp = cmdiocbq->context3; @@ -366,8 +366,8 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, lpfc_free_bsg_buffers(phba, rmp); lpfc_mbuf_free(phba, bmp->virt, bmp->phys); kfree(bmp); - lpfc_sli_release_iocbq(phba, cmdiocbq); lpfc_nlp_put(ndlp); + lpfc_sli_release_iocbq(phba, cmdiocbq); kfree(dd_data); /* Complete the job if the job is still active */ @@ -408,6 +408,9 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) /* in case no data is transferred */ bsg_reply->reply_payload_rcv_len = 0; + if (ndlp->nlp_flag & NLP_ELS_SND_MASK) + return -ENODEV; + /* allocate our bsg tracking structure */ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); if (!dd_data) { @@ -417,20 +420,10 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) goto no_dd_data; } - if (!lpfc_nlp_get(ndlp)) { - rc = -ENODEV; - goto no_ndlp; - } - - if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { - rc = -ENODEV; - goto free_ndlp; - } - cmdiocbq = lpfc_sli_get_iocbq(phba); if (!cmdiocbq) { rc = -ENOMEM; - goto free_ndlp; + goto free_dd; } cmd = &cmdiocbq->iocb; @@ -496,11 +489,10 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) cmdiocbq->context1 = dd_data; cmdiocbq->context2 = cmp; cmdiocbq->context3 = bmp; - cmdiocbq->context_un.ndlp = ndlp; + dd_data->type = TYPE_IOCB; dd_data->set_job = job; dd_data->context_un.iocb.cmdiocbq = cmdiocbq; - dd_data->context_un.iocb.ndlp = ndlp; dd_data->context_un.iocb.rmp = rmp; job->dd_data = dd_data; @@ -514,8 +506,13 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) readl(phba->HCregaddr); /* flush */ } - iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); + cmdiocbq->context_un.ndlp = lpfc_nlp_get(ndlp); + if (!cmdiocbq->context_un.ndlp) { + rc = -ENODEV; + goto free_rmp; + } + iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); if (iocb_stat == IOCB_SUCCESS) { spin_lock_irqsave(&phba->hbalock, flags); /* make sure the I/O had not been completed yet */ @@ -532,7 +529,7 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) } /* iocb failed so cleanup */ - job->dd_data = NULL; + lpfc_nlp_put(ndlp); free_rmp: lpfc_free_bsg_buffers(phba, rmp); @@ -544,9 +541,7 @@ free_bmp: kfree(bmp); free_cmdiocbq: lpfc_sli_release_iocbq(phba, cmdiocbq); -free_ndlp: - lpfc_nlp_put(ndlp); -no_ndlp: +free_dd: kfree(dd_data); no_dd_data: /* make error code available to userspace */ @@ -640,8 +635,9 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, } } - lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, cmdiocbq); + + lpfc_nlp_put(ndlp); kfree(dd_data); /* Complete the job if the job is still active */ @@ -718,15 +714,14 @@ lpfc_bsg_rport_els(struct bsg_job *job) goto release_ndlp; } - rpi = ndlp->nlp_rpi; - /* Transfer the request payload to allocated command dma buffer */ - sg_copy_to_buffer(job->request_payload.sg_list, job->request_payload.sg_cnt, ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt, cmdsize); + rpi = ndlp->nlp_rpi; + if (phba->sli_rev == LPFC_SLI_REV4) cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi]; else @@ -752,8 +747,13 @@ lpfc_bsg_rport_els(struct bsg_job *job) readl(phba->HCregaddr); /* flush */ } - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); + cmdiocbq->context1 = lpfc_nlp_get(ndlp); + if (!cmdiocbq->context1) { + rc = -EIO; + goto linkdown_err; + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); if (rc == IOCB_SUCCESS) { spin_lock_irqsave(&phba->hbalock, flags); /* make sure the I/O had not been completed/released */ @@ -769,11 +769,9 @@ lpfc_bsg_rport_els(struct bsg_job *job) rc = -EIO; } - /* iocb failed so cleanup */ - job->dd_data = NULL; + /* I/O issue failed. Cleanup resources. */ linkdown_err: - cmdiocbq->context1 = ndlp; lpfc_els_free_iocb(phba, cmdiocbq); release_ndlp: @@ -902,11 +900,8 @@ diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) return 0; } -/** +/* * lpfc_bsg_ct_unsol_event - process an unsolicited CT command - * @phba: - * @pring: - * @piocbq: * * This function is called when an unsolicited CT command is received. It * forwards the event to any processes registered to receive CT events. @@ -939,28 +934,9 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, INIT_LIST_HEAD(&head); list_add_tail(&head, &piocbq->list); - if (piocbq->iocb.ulpBdeCount == 0 || - piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) - goto error_ct_unsol_exit; - - if (phba->link_state == LPFC_HBA_ERROR || - (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) - goto error_ct_unsol_exit; - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) - dmabuf = bdeBuf1; - else { - dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, - piocbq->iocb.un.cont64[0].addrLow); - dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); - } - if (dmabuf == NULL) - goto error_ct_unsol_exit; - ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; + ct_req = (struct lpfc_sli_ct_request *)bdeBuf1; evt_req_id = ct_req->FsType; cmd = ct_req->CommandResponse.bits.CmdRsp; - if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { @@ -1474,7 +1450,8 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, * @phba: Pointer to HBA context object. * @job: Pointer to the job object. * @tag: tag index value into the ports context exchange array. - * @bmp: Pointer to a dma buffer descriptor. + * @cmp: Pointer to a cmp dma buffer descriptor. + * @bmp: Pointer to a bmp dma buffer descriptor. * @num_entry: Number of enties in the bde. **/ static int @@ -1490,6 +1467,15 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, unsigned long flags; uint32_t creg_val; + ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); + if (!ndlp) { + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, + "2721 ndlp null for oxid %x SID %x\n", + phba->ct_ctx[tag].rxid, + phba->ct_ctx[tag].SID); + return IOCB_ERROR; + } + /* allocate our bsg tracking structure */ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); if (!dd_data) { @@ -1540,12 +1526,6 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, goto issue_ct_rsp_exit; } - /* Check if the ndlp is active */ - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - rc = IOCB_ERROR; - goto issue_ct_rsp_exit; - } - /* get a refernece count so the ndlp doesn't go away while * we respond */ @@ -1580,7 +1560,11 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, dd_data->type = TYPE_IOCB; dd_data->set_job = job; dd_data->context_un.iocb.cmdiocbq = ctiocb; - dd_data->context_un.iocb.ndlp = ndlp; + dd_data->context_un.iocb.ndlp = lpfc_nlp_get(ndlp); + if (!dd_data->context_un.iocb.ndlp) { + rc = -IOCB_ERROR; + goto issue_ct_rsp_exit; + } dd_data->context_un.iocb.rmp = NULL; job->dd_data = dd_data; @@ -1595,7 +1579,6 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, } rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); - if (rc == IOCB_SUCCESS) { spin_lock_irqsave(&phba->hbalock, flags); /* make sure the I/O had not been completed/released */ @@ -1609,6 +1592,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, /* iocb failed so cleanup */ job->dd_data = NULL; + lpfc_nlp_put(ndlp); issue_ct_rsp_exit: lpfc_sli_release_iocbq(phba, ctiocb); @@ -3535,6 +3519,7 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, mb->mbxCommand); return -EPERM; } + break; case MBX_WRITE_NV: case MBX_WRITE_VPARMS: case MBX_LOAD_SM: @@ -3886,9 +3871,9 @@ lpfc_bsg_sli_cfg_dma_desc_setup(struct lpfc_hba *phba, enum nemb_type nemb_tp, /** * lpfc_bsg_sli_cfg_mse_read_cmd_ext - sli_config non-embedded mailbox cmd read * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. + * @job: Pointer to the job object. * @nemb_tp: Enumerate of non-embedded mailbox command type. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine performs SLI_CONFIG (0x9B) read mailbox command operation with * non-embedded external bufffers. @@ -4075,8 +4060,9 @@ job_error: /** * lpfc_bsg_sli_cfg_write_cmd_ext - sli_config non-embedded mailbox cmd write * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. + * @nemb_tp: Enumerate of non-embedded mailbox command type. + * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine performs SLI_CONFIG (0x9B) write mailbox command operation with * non-embedded external bufffers. @@ -4241,8 +4227,8 @@ job_error: /** * lpfc_bsg_handle_sli_cfg_mbox - handle sli-cfg mailbox cmd with ext buffer * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. + * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine handles SLI_CONFIG (0x9B) mailbox command with non-embedded * external bufffers, including both 0x9B with non-embedded MSEs and 0x9B @@ -4393,7 +4379,7 @@ lpfc_bsg_mbox_ext_abort(struct lpfc_hba *phba) /** * lpfc_bsg_read_ebuf_get - get the next mailbox read external buffer * @phba: Pointer to HBA context object. - * @dmabuf: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. * * This routine extracts the next mailbox read external buffer back to * user space through BSG. @@ -4463,6 +4449,7 @@ lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct bsg_job *job) /** * lpfc_bsg_write_ebuf_set - set the next mailbox write external buffer * @phba: Pointer to HBA context object. + * @job: Pointer to the job object. * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine sets up the next mailbox read external buffer obtained @@ -4588,8 +4575,8 @@ job_error: /** * lpfc_bsg_handle_sli_cfg_ebuf - handle ext buffer with sli-cfg mailbox cmd * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. + * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine handles the external buffer with SLI_CONFIG (0x9B) mailbox * command with multiple non-embedded external buffers. @@ -4633,8 +4620,8 @@ lpfc_bsg_handle_sli_cfg_ebuf(struct lpfc_hba *phba, struct bsg_job *job, /** * lpfc_bsg_handle_sli_cfg_ext - handle sli-cfg mailbox with external buffer * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. + * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine checkes and handles non-embedded multi-buffer SLI_CONFIG * (0x9B) mailbox commands and external buffers. @@ -4707,7 +4694,7 @@ sli_cfg_ext_error: /** * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app * @phba: Pointer to HBA context object. - * @mb: Pointer to a mailbox object. + * @job: Pointer to the job object. * @vport: Pointer to a vport object. * * Allocate a tracking object, mailbox command memory, get a mailbox @@ -5935,7 +5922,7 @@ lpfc_bsg_timeout(struct bsg_job *job) } } if (list_empty(&completions)) - lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); + lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb, NULL); spin_unlock_irqrestore(&phba->hbalock, flags); if (!list_empty(&completions)) { lpfc_sli_cancel_iocbs(phba, &completions, @@ -5972,7 +5959,7 @@ lpfc_bsg_timeout(struct bsg_job *job) } } if (list_empty(&completions)) - lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); + lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb, NULL); spin_unlock_irqrestore(&phba->hbalock, flags); if (!list_empty(&completions)) { lpfc_sli_cancel_iocbs(phba, &completions, diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 782f6f76f18a..f78e52a18b0b 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -88,8 +88,6 @@ void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_unregister_vfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); -struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *, - struct lpfc_nodelist *, int); void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int); void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_set_disctmo(struct lpfc_vport *); @@ -322,8 +320,12 @@ void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, uint32_t); +int lpfc_sli_issue_fcp_io(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag); int lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, struct lpfc_iocbq *pwqe); +int lpfc_sli4_issue_abort_iotag(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocb, void *cmpl); struct lpfc_sglq *__lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xri); struct lpfc_sglq *__lpfc_sli_get_nvmet_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq); @@ -348,7 +350,7 @@ int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t); void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *); int lpfc_sli_hbq_size(void); int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *); + struct lpfc_iocbq *, void *); int lpfc_sli_sum_iocb(struct lpfc_vport *, uint16_t, uint64_t, lpfc_ctx_cmd); int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t, uint64_t, lpfc_ctx_cmd); @@ -371,6 +373,8 @@ int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, uint32_t, uint32_t); void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); +void lpfc_sli4_abort_fcp_cmpl(struct lpfc_hba *h, struct lpfc_iocbq *i, + struct lpfc_wcqe_complete *w); void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); @@ -592,11 +596,13 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd, struct lpfc_sli4_hdw_queue *qp); void lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd); -void lpfc_nvme_cmd_template(void); +void lpfc_wqe_cmd_template(void); void lpfc_nvmet_cmd_template(void); void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn); -void lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt); extern int lpfc_enable_nvmet_cnt; extern unsigned long long lpfc_enable_nvmet[]; extern int lpfc_no_hba_reset_cnt; extern unsigned long lpfc_no_hba_reset[]; +extern union lpfc_wqe128 lpfc_iread_cmd_template; +extern union lpfc_wqe128 lpfc_iwrite_cmd_template; +extern union lpfc_wqe128 lpfc_icmnd_cmd_template; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index a8bf4d0d58f0..dd0b432f7ac5 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -99,21 +99,265 @@ lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size); } +/** + * lpfc_ct_unsol_cmpl : Completion callback function for unsol ct commands + * @phba : pointer to lpfc hba data structure. + * @cmdiocb : pointer to lpfc command iocb data structure. + * @rspiocb : pointer to lpfc response iocb data structure. + * + * This routine is the callback function for issuing unsol ct reject command. + * The memory allocated in the reject command path is freed up here. + **/ +static void +lpfc_ct_unsol_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_nodelist *ndlp; + struct lpfc_dmabuf *mp, *bmp; + + ndlp = (struct lpfc_nodelist *)cmdiocb->context1; + if (ndlp) + lpfc_nlp_put(ndlp); + + mp = cmdiocb->context2; + bmp = cmdiocb->context3; + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + cmdiocb->context2 = NULL; + } + + if (bmp) { + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + kfree(bmp); + cmdiocb->context3 = NULL; + } + + lpfc_sli_release_iocbq(phba, cmdiocb); +} + +/** + * lpfc_ct_reject_event : Issue reject for unhandled CT MIB commands + * @ndlp : pointer to a node-list data structure. + * ct_req : pointer to the CT request data structure. + * rx_id : rx_id of the received UNSOL CT command + * ox_id : ox_id of the UNSOL CT command + * + * This routine is invoked by the lpfc_ct_handle_mibreq routine for sending + * a reject response. Reject response is sent for the unhandled commands. + **/ +static void +lpfc_ct_reject_event(struct lpfc_nodelist *ndlp, + struct lpfc_sli_ct_request *ct_req, + u16 rx_id, u16 ox_id) +{ + struct lpfc_vport *vport = ndlp->vport; + struct lpfc_hba *phba = vport->phba; + struct lpfc_sli_ct_request *ct_rsp; + struct lpfc_iocbq *cmdiocbq = NULL; + struct lpfc_dmabuf *bmp = NULL; + struct lpfc_dmabuf *mp = NULL; + struct ulp_bde64 *bpl; + IOCB_t *icmd; + u8 rc = 0; + + /* fill in BDEs for command */ + mp = kmalloc(sizeof(*mp), GFP_KERNEL); + if (!mp) { + rc = 1; + goto ct_exit; + } + + mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp->phys); + if (!mp->virt) { + rc = 2; + goto ct_free_mp; + } + + /* Allocate buffer for Buffer ptr list */ + bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); + if (!bmp) { + rc = 3; + goto ct_free_mpvirt; + } + + bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &bmp->phys); + if (!bmp->virt) { + rc = 4; + goto ct_free_bmp; + } + + INIT_LIST_HEAD(&mp->list); + INIT_LIST_HEAD(&bmp->list); + + bpl = (struct ulp_bde64 *)bmp->virt; + memset(bpl, 0, sizeof(struct ulp_bde64)); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); + bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); + bpl->tus.f.bdeFlags = BUFF_TYPE_BLP_64; + bpl->tus.f.bdeSize = (LPFC_CT_PREAMBLE - 4); + bpl->tus.w = le32_to_cpu(bpl->tus.w); + + ct_rsp = (struct lpfc_sli_ct_request *)mp->virt; + memset(ct_rsp, 0, sizeof(struct lpfc_sli_ct_request)); + + ct_rsp->RevisionId.bits.Revision = SLI_CT_REVISION; + ct_rsp->RevisionId.bits.InId = 0; + ct_rsp->FsType = ct_req->FsType; + ct_rsp->FsSubType = ct_req->FsSubType; + ct_rsp->CommandResponse.bits.Size = 0; + ct_rsp->CommandResponse.bits.CmdRsp = + cpu_to_be16(SLI_CT_RESPONSE_FS_RJT); + ct_rsp->ReasonCode = SLI_CT_REQ_NOT_SUPPORTED; + ct_rsp->Explanation = SLI_CT_NO_ADDITIONAL_EXPL; + + cmdiocbq = lpfc_sli_get_iocbq(phba); + if (!cmdiocbq) { + rc = 5; + goto ct_free_bmpvirt; + } + + icmd = &cmdiocbq->iocb; + icmd->un.genreq64.bdl.ulpIoTag32 = 0; + icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); + icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); + icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + icmd->un.genreq64.bdl.bdeSize = sizeof(struct ulp_bde64); + icmd->un.genreq64.w5.hcsw.Fctl = (LS | LA); + icmd->un.genreq64.w5.hcsw.Dfctl = 0; + icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; + icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; + icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + + /* Save for completion so we can release these resources */ + cmdiocbq->context1 = lpfc_nlp_get(ndlp); + cmdiocbq->context2 = (uint8_t *)mp; + cmdiocbq->context3 = (uint8_t *)bmp; + cmdiocbq->iocb_cmpl = lpfc_ct_unsol_cmpl; + icmd->ulpContext = rx_id; /* Xri / rx_id */ + icmd->unsli3.rcvsli3.ox_id = ox_id; + icmd->un.ulpWord[3] = + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; + icmd->ulpTimeout = (3 * phba->fc_ratov); + + cmdiocbq->retry = 0; + cmdiocbq->vport = vport; + cmdiocbq->context_un.ndlp = NULL; + cmdiocbq->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); + if (!rc) + return; + + rc = 6; + lpfc_nlp_put(ndlp); + lpfc_sli_release_iocbq(phba, cmdiocbq); +ct_free_bmpvirt: + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); +ct_free_bmp: + kfree(bmp); +ct_free_mpvirt: + lpfc_mbuf_free(phba, mp->virt, mp->phys); +ct_free_mp: + kfree(mp); +ct_exit: + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "6440 Unsol CT: Rsp err %d Data: x%x\n", + rc, vport->fc_flag); +} + +/** + * lpfc_ct_handle_mibreq - Process an unsolicited CT MIB request data buffer + * @phba: pointer to lpfc hba data structure. + * @ctiocb: pointer to lpfc CT command iocb data structure. + * + * This routine is used for processing the IOCB associated with a unsolicited + * CT MIB request. It first determines whether there is an existing ndlp that + * matches the DID from the unsolicited IOCB. If not, it will return. + **/ +static void +lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq) +{ + struct lpfc_sli_ct_request *ct_req; + struct lpfc_nodelist *ndlp = NULL; + struct lpfc_vport *vport = NULL; + IOCB_t *icmd = &ctiocbq->iocb; + u32 mi_cmd, vpi; + u32 did = 0; + + vpi = ctiocbq->iocb.unsli3.rcvsli3.vpi; + vport = lpfc_find_vport_by_vpid(phba, vpi); + if (!vport) { + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "6437 Unsol CT: VPORT NULL vpi : x%x\n", + vpi); + return; + } + + did = ctiocbq->iocb.un.rcvels.remoteID; + if (icmd->ulpStatus) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6438 Unsol CT: status:x%x/x%x did : x%x\n", + icmd->ulpStatus, icmd->un.ulpWord[4], did); + return; + } + + /* Ignore traffic received during vport shutdown */ + if (vport->fc_flag & FC_UNLOADING) + return; + + ndlp = lpfc_findnode_did(vport, did); + if (!ndlp) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6439 Unsol CT: NDLP Not Found for DID : x%x", + did); + return; + } + + ct_req = ((struct lpfc_sli_ct_request *) + (((struct lpfc_dmabuf *)ctiocbq->context2)->virt)); + + mi_cmd = ct_req->CommandResponse.bits.CmdRsp; + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6442 : MI Cmd : x%x Not Supported\n", mi_cmd); + lpfc_ct_reject_event(ndlp, ct_req, + ctiocbq->iocb.ulpContext, + ctiocbq->iocb.unsli3.rcvsli3.ox_id); +} + +/** + * lpfc_ct_unsol_event - Process an unsolicited event from a ct sli ring + * @phba: pointer to lpfc hba data structure. + * @pring: pointer to a SLI ring. + * @ctiocbq: pointer to lpfc ct iocb data structure. + * + * This routine is used to process an unsolicited event received from a SLI + * (Service Level Interface) ring. The actual processing of the data buffer + * associated with the unsolicited event is done by invoking appropriate routine + * after properly set up the iocb buffer from the SLI ring on which the + * unsolicited event was received. + **/ void lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *piocbq) + struct lpfc_iocbq *ctiocbq) { struct lpfc_dmabuf *mp = NULL; - IOCB_t *icmd = &piocbq->iocb; + IOCB_t *icmd = &ctiocbq->iocb; int i; struct lpfc_iocbq *iocbq; - dma_addr_t paddr; + dma_addr_t dma_addr; uint32_t size; struct list_head head; - struct lpfc_dmabuf *bdeBuf; + struct lpfc_sli_ct_request *ct_req; + struct lpfc_dmabuf *bdeBuf1 = ctiocbq->context2; + struct lpfc_dmabuf *bdeBuf2 = ctiocbq->context3; - if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) - return; + ctiocbq->context1 = NULL; + ctiocbq->context2 = NULL; + ctiocbq->context3 = NULL; if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); @@ -127,46 +371,75 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return; } - /* If there are no BDEs associated with this IOCB, - * there is nothing to do. + /* If there are no BDEs associated + * with this IOCB, there is nothing to do. */ if (icmd->ulpBdeCount == 0) return; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + ctiocbq->context2 = bdeBuf1; + if (icmd->ulpBdeCount == 2) + ctiocbq->context3 = bdeBuf2; + } else { + dma_addr = getPaddr(icmd->un.cont64[0].addrHigh, + icmd->un.cont64[0].addrLow); + ctiocbq->context2 = lpfc_sli_ringpostbuf_get(phba, pring, + dma_addr); + if (icmd->ulpBdeCount == 2) { + dma_addr = getPaddr(icmd->un.cont64[1].addrHigh, + icmd->un.cont64[1].addrLow); + ctiocbq->context3 = lpfc_sli_ringpostbuf_get(phba, + pring, + dma_addr); + } + } + + ct_req = ((struct lpfc_sli_ct_request *) + (((struct lpfc_dmabuf *)ctiocbq->context2)->virt)); + + if (ct_req->FsType == SLI_CT_MANAGEMENT_SERVICE && + ct_req->FsSubType == SLI_CT_MIB_Subtypes) { + lpfc_ct_handle_mibreq(phba, ctiocbq); + } else { + if (!lpfc_bsg_ct_unsol_event(phba, pring, ctiocbq)) + return; + } + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); + list_add_tail(&head, &ctiocbq->list); list_for_each_entry(iocbq, &head, list) { icmd = &iocbq->iocb; if (icmd->ulpBdeCount == 0) continue; - bdeBuf = iocbq->context2; + bdeBuf1 = iocbq->context2; iocbq->context2 = NULL; size = icmd->un.cont64[0].tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size); - lpfc_in_buf_free(phba, bdeBuf); + lpfc_ct_unsol_buffer(phba, ctiocbq, bdeBuf1, size); + lpfc_in_buf_free(phba, bdeBuf1); if (icmd->ulpBdeCount == 2) { - bdeBuf = iocbq->context3; + bdeBuf2 = iocbq->context3; iocbq->context3 = NULL; size = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, + lpfc_ct_unsol_buffer(phba, ctiocbq, bdeBuf2, size); - lpfc_in_buf_free(phba, bdeBuf); + lpfc_in_buf_free(phba, bdeBuf2); } } list_del(&head); } else { INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); + list_add_tail(&head, &ctiocbq->list); list_for_each_entry(iocbq, &head, list) { icmd = &iocbq->iocb; if (icmd->ulpBdeCount == 0) lpfc_ct_unsol_buffer(phba, iocbq, NULL, 0); for (i = 0; i < icmd->ulpBdeCount; i++) { - paddr = getPaddr(icmd->un.cont64[i].addrHigh, - icmd->un.cont64[i].addrLow); + dma_addr = getPaddr(icmd->un.cont64[i].addrHigh, + icmd->un.cont64[i].addrLow); mp = lpfc_sli_ringpostbuf_get(phba, pring, - paddr); + dma_addr); size = icmd->un.cont64[i].tus.f.bdeSize; lpfc_ct_unsol_buffer(phba, iocbq, mp, size); lpfc_in_buf_free(phba, mp); @@ -275,10 +548,8 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb) { struct lpfc_dmabuf *buf_ptr; - if (ctiocb->context_un.ndlp) { - lpfc_nlp_put(ctiocb->context_un.ndlp); - ctiocb->context_un.ndlp = NULL; - } + /* I/O job is complete so context is now invalid*/ + ctiocb->context_un.ndlp = NULL; if (ctiocb->context1) { buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1; lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); @@ -345,7 +616,6 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, /* Save for completion so we can release these resources */ geniocb->context1 = (uint8_t *) inp; geniocb->context2 = (uint8_t *) outp; - geniocb->context_un.ndlp = lpfc_nlp_get(ndlp); /* Fill in payload, bp points to frame payload */ icmd->ulpCommand = CMD_GEN_REQUEST64_CR; @@ -384,16 +654,21 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; geniocb->vport = vport; geniocb->retry = retry; + geniocb->context_un.ndlp = lpfc_nlp_get(ndlp); + if (!geniocb->context_un.ndlp) + goto out; rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0); if (rc == IOCB_ERROR) { geniocb->context_un.ndlp = NULL; lpfc_nlp_put(ndlp); - lpfc_sli_release_iocbq(phba, geniocb); - return 1; + goto out; } return 0; +out: + lpfc_sli_release_iocbq(phba, geniocb); + return 1; } /* @@ -467,7 +742,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) ndlp = lpfc_setup_disc_node(vport, Did); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + if (ndlp) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "Parse GID_FTrsp: did:x%x flg:x%x x%x", Did, ndlp->nlp_flag, vport->fc_flag); @@ -518,7 +793,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) * Don't even bother to send GFF_ID. */ ndlp = lpfc_findnode_did(vport, Did); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + if (ndlp && (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET))) { if (fc4_type == FC_TYPE_FCP) @@ -550,7 +825,6 @@ lpfc_ns_rsp_audit_did(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) { struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); char *str; if (phba->cfg_ns_query == LPFC_NS_QUERY_GID_FT) @@ -579,12 +853,12 @@ lpfc_ns_rsp_audit_did(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) if (ndlp->nlp_type != NLP_NVME_INITIATOR || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) continue; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); if (ndlp->nlp_DID == Did) ndlp->nlp_flag &= ~NLP_NVMET_RECOV; else ndlp->nlp_flag |= NLP_NVMET_RECOV; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } } } @@ -600,7 +874,6 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint8_t fc4_type, uint32_t Did, CTentry; int Cnt; struct list_head head; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp = NULL; lpfc_set_disctmo(vport); @@ -646,9 +919,9 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint8_t fc4_type, continue; lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NVMET_RECOV; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } } @@ -861,8 +1134,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_disc_start(vport); } out: - cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */ lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -1068,8 +1341,8 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_disc_start(vport); } out: - cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */ lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } static void @@ -1084,7 +1357,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_sli_ct_request *CTrsp; int did, rc, retry; uint8_t fbits; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp = NULL, *free_ndlp = NULL; did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId; did = be32_to_cpu(did); @@ -1150,7 +1423,9 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cmdiocb->retry, did); if (rc == 0) { /* success */ + free_ndlp = cmdiocb->context_un.ndlp; lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); return; } } @@ -1164,7 +1439,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* This is a target port, unregistered port, or the GFF_ID failed */ ndlp = lpfc_setup_disc_node(vport, did); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + if (ndlp) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0242 Process x%x GFF " "NameServer Rsp Data: x%x x%x x%x\n", @@ -1203,7 +1478,10 @@ out: } lpfc_disc_start(vport); } + + free_ndlp = cmdiocb->context_un.ndlp; lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); return; } @@ -1217,7 +1495,8 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *)cmdiocb->context2; struct lpfc_sli_ct_request *CTrsp; int did; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp = NULL; + struct lpfc_nodelist *ns_ndlp = NULL; uint32_t fc4_data_0, fc4_data_1; did = ((struct lpfc_sli_ct_request *)inp->virt)->un.gft.PortId; @@ -1227,6 +1506,9 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "GFT_ID cmpl: status:x%x/x%x did:x%x", irsp->ulpStatus, irsp->un.ulpWord[4], did); + /* Preserve the nameserver node to release the reference. */ + ns_ndlp = cmdiocb->context_un.ndlp; + if (irsp->ulpStatus == IOSTAT_SUCCESS) { /* Good status, continue checking */ CTrsp = (struct lpfc_sli_ct_request *)outp->virt; @@ -1242,6 +1524,10 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (fc4_data_1 & LPFC_FC4_TYPE_BITMASK) ? "NVME" : " "); + /* Lookup the NPort_ID queried in the GFT_ID and find the + * driver's local node. It's an error if the driver + * doesn't have one. + */ ndlp = lpfc_findnode_did(vport, did); if (ndlp) { /* The bitmask value for FCP and NVME FCP types is @@ -1287,6 +1573,7 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "3065 GFT_ID failed x%08x\n", irsp->ulpStatus); lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ns_ndlp); } static void @@ -1356,8 +1643,8 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } out: - cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */ lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -1599,8 +1886,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, int rc = 0; ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) - || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { + if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { rc=1; goto ns_cmd_exit; } @@ -1841,11 +2127,6 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, } rc=6; - /* Decrement ndlp reference count to release ndlp reference held - * for the failed command's callback function. - */ - lpfc_nlp_put(ndlp); - ns_cmd_free_bmpvirt: lpfc_mbuf_free(phba, bmp->virt, bmp->phys); ns_cmd_free_bmp: @@ -1882,7 +2163,7 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp; uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp; IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp, *free_ndlp = NULL; uint32_t latt, cmd, err; latt = lpfc_els_chk_latt(vport); @@ -1928,10 +2209,13 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus, irsp->un.ulpWord[4]); } + + free_ndlp = cmdiocb->context_un.ndlp; lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); ndlp = lpfc_findnode_did(vport, FDMI_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) return; /* Check for a CT LS_RJT response */ @@ -1959,6 +2243,7 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR; /* Start over */ lpfc_fdmi_cmd(vport, ndlp, cmd, 0); + return; } if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) { vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR; @@ -1968,12 +2253,21 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, return; case SLI_MGMT_RPA: + /* No retry on Vendor RPA */ + if (phba->link_flag & LS_CT_VEN_RPA) { + lpfc_printf_vlog(vport, KERN_ERR, + LOG_DISCOVERY | LOG_ELS, + "6460 VEN FDMI RPA failure\n"); + phba->link_flag &= ~LS_CT_VEN_RPA; + return; + } if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) { /* Fallback to FDMI-1 */ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR; vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR; /* Start over */ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0); + return; } if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) { vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR; @@ -2004,6 +2298,33 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, else lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0); break; + case SLI_MGMT_RPA: + if (vport->port_type == LPFC_PHYSICAL_PORT && + phba->cfg_enable_mi && + phba->sli4_hba.pc_sli4_params.mi_ver > LPFC_MIB1_SUPPORT) { + /* mi is only for the phyical port, no vports */ + if (phba->link_flag & LS_CT_VEN_RPA) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_ELS, + "6449 VEN RPA Success\n"); + break; + } + + if (lpfc_fdmi_cmd(vport, ndlp, cmd, + LPFC_FDMI_VENDOR_ATTR_mi) == 0) + phba->link_flag |= LS_CT_VEN_RPA; + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_ELS, + "6458 Send MI FDMI:%x Flag x%x\n", + phba->sli4_hba.pc_sli4_params.mi_value, + phba->link_flag); + } else { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_ELS, + "6459 No FDMI VEN MI support - " + "RPA Success\n"); + } + break; } return; } @@ -2033,7 +2354,7 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport) return; ndlp = lpfc_findnode_did(vport, FDMI_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) return; /* Check if system hostname changed */ @@ -2974,6 +3295,28 @@ lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport, return size; } +static int +lpfc_fdmi_vendor_attr_mi(struct lpfc_vport *vport, + struct lpfc_fdmi_attr_def *ad) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_fdmi_attr_entry *ae; + uint32_t len, size; + char mibrevision[16]; + + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, 256); + sprintf(mibrevision, "ELXE2EM:%04d", + phba->sli4_hba.pc_sli4_params.mi_value); + strncpy(ae->un.AttrString, &mibrevision[0], sizeof(ae->un.AttrString)); + len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString)); + len += (len & 3) ? (4 - (len & 3)) : 4; + size = FOURBYTES + len; + ad->AttrLen = cpu_to_be16(size); + ad->AttrType = cpu_to_be16(RPRT_VENDOR_MI); + return size; +} + /* RHBA attribute jump table */ int (*lpfc_fdmi_hba_action[]) (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = { @@ -3025,6 +3368,7 @@ int (*lpfc_fdmi_port_action[]) lpfc_fdmi_smart_attr_port_info, /* bit20 RPRT_SMART_PORT_INFO */ lpfc_fdmi_smart_attr_qos, /* bit21 RPRT_SMART_QOS */ lpfc_fdmi_smart_attr_security, /* bit22 RPRT_SMART_SECURITY */ + lpfc_fdmi_vendor_attr_mi, /* bit23 RPRT_VENDOR_MI */ }; /** @@ -3056,7 +3400,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) return 0; cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */ @@ -3250,12 +3594,6 @@ port_out: if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, 0)) return 0; - /* - * Decrement ndlp reference count to release ndlp reference held - * for the failed command's callback function. - */ - lpfc_nlp_put(ndlp); - fdmi_cmd_free_bmpvirt: lpfc_mbuf_free(phba, bmp->virt, bmp->phys); fdmi_cmd_free_bmp: diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index c9a327b13e5c..bc79a017e1a2 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -895,8 +895,6 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) if (ndlp->nlp_type & NLP_NVME_INITIATOR) len += scnprintf(buf + len, size - len, "NVME_INITIATOR "); - len += scnprintf(buf+len, size-len, "usgmap:%x ", - ndlp->nlp_usg_map); len += scnprintf(buf+len, size-len, "refcnt:%x", kref_read(&ndlp->kref)); if (iocnt) { @@ -957,13 +955,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) len += scnprintf(buf + len, size - len, "\tRport List:\n"); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { /* local short-hand pointer. */ - spin_lock(&phba->hbalock); + spin_lock(&ndlp->lock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) nrport = rport->remoteport; else nrport = NULL; - spin_unlock(&phba->hbalock); + spin_unlock(&ndlp->lock); if (!nrport) continue; @@ -3341,7 +3339,6 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, break; case LPFC_PCI_CFG_BROWSE: /* browse all */ goto pcicfg_browse; - break; default: /* illegal count */ len = 0; @@ -4187,6 +4184,7 @@ lpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count) /** * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index * @pbuffer: The pointer to buffer to copy the read data into. + * @len: Length of the buffer. * @pque: The pointer to the queue to be read. * @index: The index into the queue entry. * @@ -4381,7 +4379,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, } } goto error_out; - break; + case LPFC_IDIAG_CQ: /* MBX complete queue */ if (phba->sli4_hba.mbx_cq && @@ -4433,7 +4431,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, } } goto error_out; - break; + case LPFC_IDIAG_MQ: /* MBX work queue */ if (phba->sli4_hba.mbx_wq && @@ -4447,7 +4445,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } goto error_out; - break; + case LPFC_IDIAG_WQ: /* ELS work queue */ if (phba->sli4_hba.els_wq && @@ -4487,9 +4485,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, } } } - goto error_out; - break; + case LPFC_IDIAG_RQ: /* HDR queue */ if (phba->sli4_hba.hdr_rq && @@ -4514,10 +4511,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } goto error_out; - break; default: goto error_out; - break; } pass_check: @@ -4766,7 +4761,7 @@ error_out: * @phba: The pointer to hba structure. * @pbuffer: The pointer to the buffer to copy the data to. * @len: The length of bytes to copied. - * @drbregid: The id to doorbell registers. + * @ctlregid: The id to doorbell registers. * * Description: * This routine reads a control register and copies its content to the diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 482e4a888dae..ea07afcb750a 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2013 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -41,6 +41,7 @@ enum lpfc_work_type { LPFC_EVT_DEV_LOSS, LPFC_EVT_FASTPATH_MGMT_EVT, LPFC_EVT_RESET_HBA, + LPFC_EVT_RECOVER_PORT }; /* structure used to queue event to the discovery tasklet */ @@ -80,6 +81,9 @@ struct lpfc_nodelist { struct list_head nlp_listp; struct lpfc_name nlp_portname; struct lpfc_name nlp_nodename; + + spinlock_t lock; /* Node management lock */ + uint32_t nlp_flag; /* entry flags */ uint32_t nlp_DID; /* FC D_ID of entry */ uint32_t nlp_last_elscmd; /* Last ELS cmd sent */ @@ -115,12 +119,6 @@ struct lpfc_nodelist { u8 nlp_nvme_info; /* NVME NSLER Support */ #define NLP_NVME_NSLER 0x1 /* NVME NSLER device */ - uint16_t nlp_usg_map; /* ndlp management usage bitmap */ -#define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */ -#define NLP_USG_IACT_REQ_BIT 0x2 /* Request to inactivate ndlp */ -#define NLP_USG_FREE_REQ_BIT 0x4 /* Request to invoke ndlp memory free */ -#define NLP_USG_FREE_ACK_BIT 0x8 /* Indicate ndlp memory free invoked */ - struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ struct lpfc_hba *phba; struct fc_rport *rport; /* scsi_transport_fc port structure */ @@ -128,6 +126,7 @@ struct lpfc_nodelist { struct lpfc_vport *vport; struct lpfc_work_evt els_retry_evt; struct lpfc_work_evt dev_loss_evt; + struct lpfc_work_evt recovery_evt; struct kref kref; atomic_t cmd_pending; uint32_t cmd_qdepth; @@ -135,13 +134,17 @@ struct lpfc_nodelist { unsigned long *active_rrqs_xri_bitmap; struct lpfc_scsicmd_bkt *lat_data; /* Latency data */ uint32_t fc4_prli_sent; - uint32_t upcall_flags; + uint32_t fc4_xpt_flags; #define NLP_WAIT_FOR_UNREG 0x1 +#define SCSI_XPT_REGD 0x2 +#define NVME_XPT_REGD 0x4 + uint32_t nvme_fb_size; /* NVME target's supported byte cnt */ #define NVME_FB_BIT_SHIFT 9 /* PRLI Rsp first burst in 512B units. */ uint32_t nlp_defer_did; }; + struct lpfc_node_rrq { struct list_head list; uint16_t xritag; @@ -170,7 +173,7 @@ struct lpfc_node_rrq { #define NLP_NVMET_RECOV 0x00001000 /* NVMET auditing node for recovery. */ #define NLP_FCP_PRLI_RJT 0x00002000 /* Rport does not support FCP PRLI. */ #define NLP_UNREG_INP 0x00008000 /* UNREG_RPI cmd is in progress */ -#define NLP_DEFER_RM 0x00010000 /* Remove this ndlp if no longer used */ +#define NLP_DROPPED 0x00010000 /* Init ref count has been dropped */ #define NLP_DELAY_TMO 0x00020000 /* delay timeout is running for node */ #define NLP_NPR_2B_DISC 0x00040000 /* node is included in num_disc_nodes */ #define NLP_RCV_PLOGI 0x00080000 /* Rcv'ed PLOGI from remote system */ @@ -189,32 +192,6 @@ struct lpfc_node_rrq { #define NLP_FIRSTBURST 0x40000000 /* Target supports FirstBurst */ #define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */ - -/* ndlp usage management macros */ -#define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \ - & NLP_USG_NODE_ACT_BIT) \ - && \ - !((ndlp)->nlp_usg_map \ - & NLP_USG_FREE_ACK_BIT)) -#define NLP_SET_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_NODE_ACT_BIT) -#define NLP_INT_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ - = NLP_USG_NODE_ACT_BIT) -#define NLP_CLR_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ - &= ~NLP_USG_NODE_ACT_BIT) -#define NLP_CHK_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ - & NLP_USG_IACT_REQ_BIT) -#define NLP_SET_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_IACT_REQ_BIT) -#define NLP_CHK_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ - & NLP_USG_FREE_REQ_BIT) -#define NLP_SET_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_FREE_REQ_BIT) -#define NLP_CHK_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ - & NLP_USG_FREE_ACK_BIT) -#define NLP_SET_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_FREE_ACK_BIT) - /* There are 4 different double linked lists nodelist entries can reside on. * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used * when Link Up discovery or Registered State Change Notification (RSCN) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b60945182db8..96c087b8b474 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -300,10 +300,6 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, bpl->tus.w = le32_to_cpu(bpl->tus.w); } - /* prevent preparing iocb with NULL ndlp reference */ - elsiocb->context1 = lpfc_nlp_get(ndlp); - if (!elsiocb->context1) - goto els_iocb_free_pbuf_exit; elsiocb->context2 = pcmd; elsiocb->context3 = pbuflist; elsiocb->retry = retry; @@ -378,7 +374,7 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) sp = &phba->fc_fabparam; ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { err = 1; goto fail; } @@ -418,10 +414,14 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) * for the callback routine. */ mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) { + err = 6; + goto fail_no_ndlp; + } rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - err = 6; + err = 7; goto fail_issue_reg_login; } @@ -432,6 +432,7 @@ fail_issue_reg_login: * for the failed mbox command. */ lpfc_nlp_put(ndlp); +fail_no_ndlp: mp = (struct lpfc_dmabuf *)mbox->ctx_buf; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); @@ -471,7 +472,7 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) !(phba->link_flag & LS_LOOPBACK_MODE) && !(vport->fc_flag & FC_PT2PT)) { ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { rc = -ENODEV; goto fail; } @@ -765,14 +766,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ list_for_each_entry_safe(np, next_np, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(np)) - continue; if ((np->nlp_state != NLP_STE_NPR_NODE) || !(np->nlp_flag & NLP_NPR_ADISC)) continue; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&np->lock); np->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&np->lock); lpfc_unreg_rpi(vport, np); } lpfc_cleanup_pending_mbox(vport); @@ -908,11 +907,6 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp = lpfc_nlp_init(vport, PT2PT_RemoteID); if (!ndlp) goto fail; - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if(!ndlp) - goto fail; } memcpy(&ndlp->nlp_portname, &sp->portName, @@ -921,9 +915,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, sizeof(struct lpfc_name)); /* Set state will put ndlp onto node list if not already done */ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) @@ -1095,6 +1089,7 @@ stop_rr_fcf_flogi: /* Do not register VFI if the driver aborted FLOGI */ if (!lpfc_error_lost_link(irsp)) lpfc_issue_reg_vfi(vport); + lpfc_nlp_put(ndlp); goto out; } @@ -1156,6 +1151,7 @@ stop_rr_fcf_flogi: phba->fcf.current_rec.fabric_name[5], phba->fcf.current_rec.fabric_name[6], phba->fcf.current_rec.fabric_name[7]); + lpfc_nlp_put(ndlp); spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag &= ~FCF_DISCOVERY; @@ -1187,7 +1183,6 @@ flogifail: spin_unlock_irq(&phba->hbalock); lpfc_nlp_put(ndlp); - if (!lpfc_error_lost_link(irsp)) { /* FLOGI failed, so just use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); @@ -1205,6 +1200,7 @@ flogifail: } out: lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } /** @@ -1344,7 +1340,13 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "Issue FLOGI: opt:x%x", phba->sli3_options, 0, 0); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto out; + rc = lpfc_issue_fabric_iocb(phba, elsiocb); + if (rc == IOCB_ERROR) + lpfc_nlp_put(ndlp); phba->hba_flag |= HBA_FLOGI_ISSUED; @@ -1374,11 +1376,11 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, vport->fc_myDID = did; } - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; + if (!rc) + return 0; + out: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -1421,9 +1423,9 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba) icmd = &iocb->iocb; if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { ndlp = (struct lpfc_nodelist *)(iocb->context1); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (ndlp->nlp_DID == Fabric_DID)) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + if (ndlp && (ndlp->nlp_DID == Fabric_DID)) + lpfc_sli_issue_abort_iotag(phba, pring, iocb, + NULL); } } spin_unlock_irq(&phba->hbalock); @@ -1464,13 +1466,9 @@ lpfc_initial_flogi(struct lpfc_vport *vport) return 0; /* Set the node type */ ndlp->nlp_type |= NLP_FABRIC; + /* Put ndlp onto node list */ lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 0; } if (lpfc_issue_els_flogi(vport, ndlp, 0)) { @@ -1511,13 +1509,12 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) ndlp = lpfc_nlp_init(vport, Fabric_DID); if (!ndlp) return 0; + + /* NPIV is only supported in Fabrics. */ + ndlp->nlp_type |= NLP_FABRIC; + /* Put ndlp onto node list */ lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 0; } if (lpfc_issue_els_fdisc(vport, ndlp, 0)) { @@ -1562,7 +1559,7 @@ lpfc_more_plogi(struct lpfc_vport *vport) } /** - * lpfc_plogi_confirm_nport - Confirm pologi wwpn matches stored ndlp + * lpfc_plogi_confirm_nport - Confirm plogi wwpn matches stored ndlp * @phba: pointer to lpfc hba data structure. * @prsp: pointer to response IOCB payload. * @ndlp: pointer to a node-list data structure. @@ -1597,10 +1594,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, struct lpfc_nodelist *ndlp) { struct lpfc_vport *vport = ndlp->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *new_ndlp; - struct lpfc_rport_data *rdata; - struct fc_rport *rport; struct serv_parm *sp; uint8_t name[sizeof(struct lpfc_name)]; uint32_t rc, keepDID = 0, keep_nlp_flag = 0; @@ -1608,8 +1602,6 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, uint16_t keep_nlp_state; u32 keep_nlp_fc4_type = 0; struct lpfc_nvme_rport *keep_nrport = NULL; - int put_node; - int put_rport; unsigned long *active_rrqs_xri_bitmap = NULL; /* Fabric nodes can have the same WWPN so we don't bother searching @@ -1627,7 +1619,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName); /* return immediately if the WWPN matches ndlp */ - if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp)) + if (new_ndlp == ndlp) return ndlp; if (phba->sli_rev == LPFC_SLI_REV4) { @@ -1662,28 +1654,6 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, phba->active_rrq_pool); return ndlp; } - } else if (!NLP_CHK_NODE_ACT(new_ndlp)) { - rc = memcmp(&ndlp->nlp_portname, name, - sizeof(struct lpfc_name)); - if (!rc) { - if (active_rrqs_xri_bitmap) - mempool_free(active_rrqs_xri_bitmap, - phba->active_rrq_pool); - return ndlp; - } - new_ndlp = lpfc_enable_node(vport, new_ndlp, - NLP_STE_UNUSED_NODE); - if (!new_ndlp) { - if (active_rrqs_xri_bitmap) - mempool_free(active_rrqs_xri_bitmap, - phba->active_rrq_pool); - return ndlp; - } - keepDID = new_ndlp->nlp_DID; - if ((phba->sli_rev == LPFC_SLI_REV4) && active_rrqs_xri_bitmap) - memcpy(active_rrqs_xri_bitmap, - new_ndlp->active_rrqs_xri_bitmap, - phba->cfg_rrq_xri_bitmap_sz); } else { keepDID = new_ndlp->nlp_DID; if (phba->sli_rev == LPFC_SLI_REV4 && @@ -1711,7 +1681,9 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, ndlp->active_rrqs_xri_bitmap, phba->cfg_rrq_xri_bitmap_sz); - spin_lock_irq(shost->host_lock); + /* Lock both ndlps */ + spin_lock_irq(&ndlp->lock); + spin_lock_irq(&new_ndlp->lock); keep_new_nlp_flag = new_ndlp->nlp_flag; keep_nlp_flag = ndlp->nlp_flag; new_ndlp->nlp_flag = ndlp->nlp_flag; @@ -1742,7 +1714,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, else ndlp->nlp_flag &= ~NLP_RPI_REGISTERED; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&new_ndlp->lock); + spin_unlock_irq(&ndlp->lock); /* Set nlp_states accordingly */ keep_nlp_state = new_ndlp->nlp_state; @@ -1761,36 +1734,6 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, "3179 PLOGI confirm NEW: %x %x\n", new_ndlp->nlp_DID, keepDID); - /* Fix up the rport accordingly */ - rport = ndlp->rport; - if (rport) { - rdata = rport->dd_data; - if (rdata->pnode == ndlp) { - /* break the link before dropping the ref */ - ndlp->rport = NULL; - lpfc_nlp_put(ndlp); - rdata->pnode = lpfc_nlp_get(new_ndlp); - new_ndlp->rport = rport; - } - new_ndlp->nlp_type = ndlp->nlp_type; - } - - /* Fix up the nvme rport */ - if (ndlp->nrport) { - ndlp->nrport = NULL; - lpfc_nlp_put(ndlp); - } - - /* We shall actually free the ndlp with both nlp_DID and - * nlp_portname fields equals 0 to avoid any ndlp on the - * nodelist never to be used. - */ - if (ndlp->nlp_DID == 0) { - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - } - /* Two ndlps cannot have the same did on the nodelist. * Note: for this case, ndlp has a NULL WWPN so setting * the nlp_fc4_type isn't required. @@ -1803,10 +1746,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, active_rrqs_xri_bitmap, phba->cfg_rrq_xri_bitmap_sz); - if (!NLP_CHK_NODE_ACT(ndlp)) - lpfc_drop_node(vport, ndlp); - } - else { + } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3180 PLOGI confirm SWAP: %x %x\n", new_ndlp->nlp_DID, keepDID); @@ -1833,29 +1773,16 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) keep_nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_set_state(vport, ndlp, keep_nlp_state); - - /* Previous ndlp no longer active with nvme host transport. - * Remove reference from earlier registration unless the - * nvme host took care of it. - */ - if (ndlp->nrport) - lpfc_nlp_put(ndlp); ndlp->nrport = keep_nrport; - - /* Fix up the rport accordingly */ - rport = ndlp->rport; - if (rport) { - rdata = rport->dd_data; - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); - } } + + /* + * If ndlp is not associated with any rport we can drop it here else + * let dev_loss_tmo_callbk trigger DEVICE_RM event + */ + if (!ndlp->rport && (ndlp->nlp_state == NLP_STE_NPR_NODE)) + lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); + if (phba->sli_rev == LPFC_SLI_REV4 && active_rrqs_xri_bitmap) mempool_free(active_rrqs_xri_bitmap, @@ -1933,7 +1860,7 @@ lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->un.elsreq64.remoteID); ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ndlp != rrq->ndlp) { + if (!ndlp || ndlp != rrq->ndlp) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2882 RRQ completes to NPort x%x " "with no ndlp. Data: x%x x%x x%x\n", @@ -1966,7 +1893,9 @@ lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, out: if (rrq) lpfc_clr_rrq_active(phba, rrq->xritag, rrq); + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } /** @@ -1996,7 +1925,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp, *free_ndlp; struct lpfc_dmabuf *prsp; int disc; @@ -2010,23 +1939,23 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->un.elsreq64.remoteID); ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0136 PLOGI completes to NPort x%x " "with no ndlp. Data: x%x x%x x%x\n", irsp->un.elsreq64.remoteID, irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpIoTag); - goto out; + goto out_freeiocb; } /* Since ndlp can be freed in the disc state machine, note if this node * is being used during discovery. */ - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* PLOGI completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -2038,9 +1967,9 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); goto out; } @@ -2049,9 +1978,9 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ if (disc) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } goto out; } @@ -2064,10 +1993,25 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "2753 PLOGI failure DID:%06X Status:x%x/x%x\n", ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4]); + /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (!lpfc_error_lost_link(irsp)) + if (lpfc_error_lost_link(irsp)) + goto check_plogi; + else lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_PLOGI); + + /* As long as this node is not registered with the scsi or nvme + * transport, it is no longer an active node. Otherwise + * devloss handles the final cleanup. + */ + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(&ndlp->lock); + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_DEVICE_RM); + } } else { /* Good status, call state machine */ prsp = list_entry(((struct lpfc_dmabuf *) @@ -2075,9 +2019,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf, list); ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp); lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_PLOGI); + NLP_EVT_CMPL_PLOGI); } + check_plogi: if (disc && vport->num_disc_nodes) { /* Check to see if there are more PLOGIs to be sent */ lpfc_more_plogi(vport); @@ -2093,7 +2038,16 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } out: + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, + "PLOGI Cmpl PUT: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + +out_freeiocb: + /* Release the reference on the original I/O request. */ + free_ndlp = (struct lpfc_nodelist *)cmdiocb->context1; + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); return; } @@ -2122,7 +2076,6 @@ int lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) { struct lpfc_hba *phba = vport->phba; - struct Scsi_Host *shost; struct serv_parm *sp; struct lpfc_nodelist *ndlp; struct lpfc_iocbq *elsiocb; @@ -2151,8 +2104,6 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) ndlp->nlp_defer_did = did; return 0; } - if (!NLP_CHK_NODE_ACT(ndlp)) - ndlp = NULL; } /* If ndlp is not NULL, we will bump the reference count on it */ @@ -2162,10 +2113,9 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) if (!elsiocb) return 1; - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_FCP_PRLI_RJT; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); @@ -2207,13 +2157,24 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) phba->fc_stat.elsXmitPLOGI++; elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi; - ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (ret == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue PLOGI: did:x%x refcnt %d", + did, kref_read(&ndlp->kref), 0); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto io_err; + + ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (ret) { + lpfc_nlp_put(ndlp); + goto io_err; } return 0; + + io_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -2234,7 +2195,6 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; struct lpfc_nodelist *ndlp; char *mode; @@ -2245,13 +2205,13 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp = &(rspiocb->iocb); ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_PRLI_SND; /* Driver supports multiple FC4 types. Counters matter. */ vport->fc_prli_sent--; ndlp->fc4_prli_sent--; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "PRLI cmpl: status:x%x/x%x did:x%x", @@ -2301,6 +2261,20 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, else lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI); + + /* As long as this node is not registered with the SCSI + * or NVMe transport and no other PRLIs are outstanding, + * it is no longer an active node. Otherwise devloss + * handles the final cleanup. + */ + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) && + !ndlp->fc4_prli_sent) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(&ndlp->lock); + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_DEVICE_RM); + } } else { /* Good status, call state machine. However, if another * PRLI is outstanding, don't call the state machine @@ -2313,6 +2287,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, out: lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -2341,7 +2316,7 @@ int lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + int rc = 0; struct lpfc_hba *phba = vport->phba; PRLI *npr; struct lpfc_nvme_prli *npr_nvme; @@ -2476,13 +2451,9 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, local_nlp_type &= ~NLP_FC4_NVME; } - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue PRLI: did:x%x", - ndlp->nlp_DID, 0, 0); - phba->fc_stat.elsXmitPRLI++; elsiocb->iocb_cmpl = lpfc_cmpl_els_prli; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_PRLI_SND; /* The vport counters are used for lpfc_scan_finished, but @@ -2491,15 +2462,18 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ vport->fc_prli_sent++; ndlp->fc4_prli_sent++; - spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_PRLI_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + spin_unlock_irq(&ndlp->lock); + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue PRLI: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto io_err; + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + goto node_err; /* The driver supports 2 FC4 types. Make sure @@ -2508,8 +2482,17 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (phba->sli_rev == LPFC_SLI_REV4 && local_nlp_type & (NLP_FC4_FCP | NLP_FC4_NVME)) goto send_next_prli; + else + return 0; - return 0; + node_err: + lpfc_nlp_put(ndlp); + io_err: + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_PRLI_SND; + spin_unlock_irq(&ndlp->lock); + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -2650,7 +2633,6 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; struct lpfc_nodelist *ndlp; int disc; @@ -2669,10 +2651,10 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Since ndlp can be freed in the disc state machine, note if this node * is being used during discovery. */ - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* ADISC completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0104 ADISC completes to NPort x%x " @@ -2681,9 +2663,9 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpTimeout, disc, vport->num_disc_nodes); /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); goto out; } @@ -2692,9 +2674,9 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ if (disc) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_set_disctmo(vport); } goto out; @@ -2705,19 +2687,35 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4]); /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (!lpfc_error_lost_link(irsp)) + if (lpfc_error_lost_link(irsp)) + goto check_adisc; + else lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_ADISC); + + /* As long as this node is not registered with the SCSI or NVMe + * transport, it is no longer an active node. Otherwise + * devloss handles the final cleanup. + */ + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(&ndlp->lock); + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_DEVICE_RM); + } } else /* Good status, call state machine */ lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_ADISC); + check_adisc: /* Check to see if there are more ADISCs to be sent */ if (disc && vport->num_disc_nodes) lpfc_more_adisc(vport); out: lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -2745,7 +2743,7 @@ int lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + int rc = 0; struct lpfc_hba *phba = vport->phba; ADISC *ap; struct lpfc_iocbq *elsiocb; @@ -2771,24 +2769,31 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); ap->DID = be32_to_cpu(vport->fc_myDID); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue ADISC: did:x%x", - ndlp->nlp_DID, 0, 0); - phba->fc_stat.elsXmitADISC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_ADISC_SND; - spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_ADISC_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + spin_unlock_irq(&ndlp->lock); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue ADISC: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + goto io_err; return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_ADISC_SND; + spin_unlock_irq(&ndlp->lock); + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -2809,7 +2814,6 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; struct lpfc_vport *vport = ndlp->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; struct lpfcMboxq *mbox; unsigned long flags; @@ -2819,9 +2823,9 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cmdiocb->context_un.rsp_iocb = rspiocb; irsp = &(rspiocb->iocb); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "LOGO cmpl: status:x%x/x%x did:x%x", @@ -2831,8 +2835,9 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* LOGO completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0105 LOGO completes to NPort x%x " - "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], + "refcnt %d nflags x%x Data: x%x x%x x%x x%x\n", + ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag, + irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout, vport->num_disc_nodes); if (lpfc_els_chk_latt(vport)) { @@ -2840,17 +2845,6 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } - /* Check to see if link went down during discovery */ - if (ndlp->nlp_flag & NLP_TARGET_REMOVE) { - /* NLP_EVT_DEVICE_RM should unregister the RPI - * which should abort all outstanding IOs. - */ - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_DEVICE_RM); - skip_recovery = 1; - goto out; - } - /* The LOGO will not be retried on failure. A LOGO was * issued to the remote rport and a ACC or RJT or no Answer are * all acceptable. Note the failure and move forward with @@ -2872,8 +2866,24 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Call state machine. This will unregister the rpi if needed. */ lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO); + /* The driver sets this flag for an NPIV instance that doesn't want to + * log into the remote port. + */ + if (ndlp->nlp_flag & NLP_TARGET_REMOVE) { + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_DEVICE_RM); + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); + + /* Presume the node was released. */ + return; + } + out: + /* Driver is done with the IO. */ lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); + /* If we are in pt2pt mode, we could rcv new S_ID on PLOGI */ if ((vport->fc_flag & FC_PT2PT) && !(vport->fc_flag & FC_PT2PT_PLOGI)) { @@ -2908,9 +2918,9 @@ out: if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET) && skip_recovery == 0) { lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irqsave(shost->host_lock, flags); + spin_lock_irqsave(&ndlp->lock, flags); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irqrestore(shost->host_lock, flags); + spin_unlock_irqrestore(&ndlp->lock, flags); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3187 LOGO completes to NPort x%x: Start " @@ -2919,8 +2929,21 @@ out: irsp->un.ulpWord[4], irsp->ulpTimeout, vport->num_disc_nodes); lpfc_disc_start(vport); + return; + } + + /* Cleanup path for failed REG_RPI handling. If REG_RPI fails, the + * driver sends a LOGO to the rport to cleanup. For fabric and + * initiator ports cleanup the node as long as it the node is not + * register with the transport. + */ + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(&ndlp->lock); + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_DEVICE_RM); } - return; } /** @@ -2949,19 +2972,18 @@ int lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; int rc; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); if (ndlp->nlp_flag & NLP_LOGO_SND) { - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return 0; } - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, @@ -2978,30 +3000,37 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, pcmd += sizeof(uint32_t); memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name)); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue LOGO: did:x%x", - ndlp->nlp_DID, 0, 0); - phba->fc_stat.elsXmitLOGO++; elsiocb->iocb_cmpl = lpfc_cmpl_els_logo; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_SND; ndlp->nlp_flag &= ~NLP_ISSUE_LOGO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue LOGO: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + if (rc == IOCB_ERROR) + goto io_err; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_prev_state = ndlp->nlp_state; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_nlp_set_state(vport, ndlp, NLP_STE_LOGO_ISSUE); return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_LOGO_SND; + spin_unlock_irq(&ndlp->lock); + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -3024,6 +3053,7 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; + struct lpfc_nodelist *free_ndlp; IOCB_t *irsp; irsp = &rspiocb->iocb; @@ -3041,7 +3071,11 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check to see if link went down during discovery */ lpfc_els_chk_latt(vport); + + free_ndlp = (struct lpfc_nodelist *)cmdiocb->context1; + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); } /** @@ -3065,6 +3099,7 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf *pcmd, *prsp; u32 *pdata; u32 cmd; + struct lpfc_nodelist *ndlp = cmdiocb->context1; irsp = &rspiocb->iocb; @@ -3143,6 +3178,7 @@ out: /* Check to see if link went down during discovery */ lpfc_els_chk_latt(vport); lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -3170,6 +3206,7 @@ out: int lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) { + int rc = 0; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; @@ -3184,22 +3221,13 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) if (!ndlp) return 1; lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 1; } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_SCR); - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); + if (!elsiocb) return 1; - } pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); @@ -3216,22 +3244,26 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) phba->fc_stat.elsXmitSCR++; elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the rlease of - * the node. - */ - lpfc_nlp_put(ndlp); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - /* This will cause the callback-function lpfc_cmpl_els_cmd to - * trigger the release of node. - */ - if (!(vport->fc_flag & FC_PT2PT)) - lpfc_nlp_put(ndlp); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue SCR: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + goto io_err; + + /* Keep the ndlp just in case RDF is being sent */ return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -3257,6 +3289,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) { + int rc = 0; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; struct lpfc_nodelist *ndlp; @@ -3287,24 +3320,14 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) if (!ndlp) return 1; lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - return 1; } } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_RSCN_XMT); - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); + if (!elsiocb) return 1; - } event = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; @@ -3319,29 +3342,31 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) event->portid.rscn_fid[1] = (nportid & 0x0000FF00) >> 8; event->portid.rscn_fid[2] = nportid & 0x000000FF; + phba->fc_stat.elsXmitRSCN++; + elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue RSCN: did:x%x", ndlp->nlp_DID, 0, 0); - phba->fc_stat.elsXmitRSCN++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the rlease of - * the node. - */ - lpfc_nlp_put(ndlp); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + goto io_err; + /* This will cause the callback-function lpfc_cmpl_els_cmd to * trigger the release of node. */ if (!(vport->fc_flag & FC_PT2PT)) lpfc_nlp_put(ndlp); - return 0; +io_err: + lpfc_nlp_put(ndlp); +node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -3369,6 +3394,7 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) static int lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) { + int rc = 0; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; FARP *fp; @@ -3386,21 +3412,12 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) if (!ndlp) return 1; lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 1; } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_RNID); - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); + if (!elsiocb) return 1; - } pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); @@ -3419,7 +3436,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name)); memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); ondlp = lpfc_findnode_did(vport, nportid); - if (ondlp && NLP_CHK_NODE_ACT(ondlp)) { + if (ondlp) { memcpy(&fp->OportName, &ondlp->nlp_portname, sizeof(struct lpfc_name)); memcpy(&fp->OnodeName, &ondlp->nlp_nodename, @@ -3432,8 +3449,14 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) phba->fc_stat.elsXmitFARPR++; elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { /* The additional lpfc_nlp_put will cause the following * lpfc_els_free_iocb routine to trigger the release of * the node. @@ -3474,6 +3497,7 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) struct lpfc_els_rdf_req *prdf; struct lpfc_nodelist *ndlp; uint16_t cmdsize; + int rc; cmdsize = sizeof(*prdf); @@ -3483,10 +3507,6 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) if (!ndlp) return -ENODEV; lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return -ENODEV; } /* RDF ELS is not required on an NPIV VN_Port. */ @@ -3497,13 +3517,8 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_RDF); - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); + if (!elsiocb) return -ENOMEM; - } /* Configure the payload for the supported FPIN events. */ prdf = (struct lpfc_els_rdf_req *) @@ -3521,31 +3536,29 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) prdf->reg_d1.desc_tags[2] = cpu_to_be32(ELS_DTAG_PEER_CONGEST); prdf->reg_d1.desc_tags[3] = cpu_to_be32(ELS_DTAG_CONGESTION); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue RDF: did:x%x", - ndlp->nlp_DID, 0, 0); - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "6444 Xmit RDF to remote NPORT x%x\n", ndlp->nlp_DID); elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the rlease of - * the node. - */ - lpfc_nlp_put(ndlp); - lpfc_els_free_iocb(phba, elsiocb); - return -EIO; - } + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; - /* An RDF was issued - this put ensures the ndlp is cleaned up - * when the RDF completes. - */ - lpfc_nlp_put(ndlp); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue RDF: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + goto io_err; return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); + return -EIO; } /** @@ -3568,9 +3581,9 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) if (!(nlp->nlp_flag & NLP_DELAY_TMO)) return; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&nlp->lock); nlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&nlp->lock); del_timer_sync(&nlp->nlp_delayfunc); nlp->nlp_last_elscmd = 0; if (!list_empty(&nlp->els_retry_evt.evt_listp)) { @@ -3580,9 +3593,9 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); } if (nlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&nlp->lock); nlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&nlp->lock); if (vport->num_disc_nodes) { if (vport->port_state < LPFC_VPORT_READY) { /* Check if there are more ADISCs to be sent */ @@ -3658,20 +3671,19 @@ void lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) { struct lpfc_vport *vport = ndlp->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); uint32_t cmd, retry; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); cmd = ndlp->nlp_last_elscmd; ndlp->nlp_last_elscmd = 0; if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return; } ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* * If a discovery event readded nlp_delayfunc after timer * firing and before processing the timer, cancel the @@ -3800,7 +3812,6 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp = &rspiocb->iocb; struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; @@ -3822,14 +3833,13 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cmd = *elscmd++; } - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) + if (ndlp) did = ndlp->nlp_DID; else { /* We should only hit this case for retrying PLOGI */ did = irsp->un.elsreq64.remoteID; ndlp = lpfc_findnode_did(vport, did); - if ((!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - && (cmd != ELS_CMD_PLOGI)) + if (!ndlp && (cmd != ELS_CMD_PLOGI)) return 1; } @@ -4059,9 +4069,9 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ if (stat.un.b.lsRjtRsnCodeExp == LSEXP_REQ_UNSUPPORTED && cmd == ELS_CMD_PRLI) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_FCP_PRLI_RJT; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); retry = 0; goto out_retry; } @@ -4157,16 +4167,16 @@ out_retry: } phba->fc_stat.elsXmitRetry++; - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && delay) { + if (ndlp && delay) { phba->fc_stat.elsDelayRetry++; ndlp->nlp_retry = cmdiocb->retry; /* delay is specified in milliseconds */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(delay)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_prev_state = ndlp->nlp_state; if ((cmd == ELS_CMD_PRLI) || @@ -4188,7 +4198,7 @@ out_retry: lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry); return 1; case ELS_CMD_PLOGI: - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + if (ndlp) { ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); @@ -4314,27 +4324,10 @@ int lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) { struct lpfc_dmabuf *buf_ptr, *buf_ptr1; - struct lpfc_nodelist *ndlp; - ndlp = (struct lpfc_nodelist *)elsiocb->context1; - if (ndlp) { - if (ndlp->nlp_flag & NLP_DEFER_RM) { - lpfc_nlp_put(ndlp); + /* The I/O job is complete. Clear the context1 data. */ + elsiocb->context1 = NULL; - /* If the ndlp is not being used by another discovery - * thread, free it. - */ - if (!lpfc_nlp_not_used(ndlp)) { - /* If ndlp is being used by another discovery - * thread, just clear NLP_DEFER_RM - */ - ndlp->nlp_flag &= ~NLP_DEFER_RM; - } - } - else - lpfc_nlp_put(ndlp); - elsiocb->context1 = NULL; - } /* context2 = cmd, context2->next = rsp, context3 = bpl */ if (elsiocb->context2) { if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) { @@ -4409,10 +4402,10 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID); /* ACC to LOGO completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0109 ACC to LOGO completes to NPort x%x " + "0109 ACC to LOGO completes to NPort x%x refcnt %d" "Data: x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); + ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag, + ndlp->nlp_state, ndlp->nlp_rpi); if (ndlp->nlp_state == NLP_STE_NPR_NODE) { /* NPort Recovery mode or node is just allocated */ @@ -4434,6 +4427,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * At this point, the driver is done so release the IOCB */ lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } /** @@ -4463,20 +4457,17 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mempool_free(pmb, phba->mbox_mem_pool); if (ndlp) { lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0006 rpi%x DID:%x flg:%x %d map:%x x%px\n", + "0006 rpi x%x DID:%x flg:%x %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); - if (NLP_CHK_NODE_ACT(ndlp)) { - lpfc_nlp_put(ndlp); - /* This is the end of the default RPI cleanup logic for - * this ndlp. If no other discovery threads are using - * this ndlp, free all resources associated with it. - */ - lpfc_nlp_not_used(ndlp); - } else { - lpfc_drop_node(ndlp->vport, ndlp); - } + ndlp); + /* This is the end of the default RPI cleanup logic for + * this ndlp and it could get released. Clear the nlp_flags to + * prevent any further processing. + */ + ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + lpfc_nlp_put(ndlp); + lpfc_nlp_not_used(ndlp); } return; @@ -4525,8 +4516,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * function can have cmdiocb->contest1 (ndlp) field set to NULL. */ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) { + if (ndlp && (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) { /* A LS_RJT associated with Default RPI cleanup has its own * separate code path. */ @@ -4535,7 +4525,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } /* Check to see if link went down during discovery */ - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || lpfc_els_chk_latt(vport)) { + if (!ndlp || lpfc_els_chk_latt(vport)) { if (mbox) { mp = (struct lpfc_dmabuf *)mbox->ctx_buf; if (mp) { @@ -4544,8 +4534,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } mempool_free(mbox, phba->mbox_mem_pool); } - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (ndlp->nlp_flag & NLP_RM_DFLT_RPI)) + if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI)) if (lpfc_nlp_not_used(ndlp)) { ndlp = NULL; /* Indicate the node has already released, @@ -4570,32 +4559,38 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); if (mbox) { - if ((rspiocb->iocb.ulpStatus == 0) - && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { + if ((rspiocb->iocb.ulpStatus == 0) && + (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { if (!lpfc_unreg_rpi(vport, ndlp) && - (!(vport->fc_flag & FC_PT2PT)) && - (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || - ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE)) { - lpfc_printf_vlog(vport, KERN_INFO, - LOG_DISCOVERY, - "0314 PLOGI recov DID x%x " - "Data: x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_state, - ndlp->nlp_rpi, ndlp->nlp_flag); - mp = mbox->ctx_buf; - if (mp) { - lpfc_mbuf_free(phba, mp->virt, - mp->phys); - kfree(mp); + (!(vport->fc_flag & FC_PT2PT))) { + if (ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY, + "0314 PLOGI recov " + "DID x%x " + "Data: x%x x%x x%x\n", + ndlp->nlp_DID, + ndlp->nlp_state, + ndlp->nlp_rpi, + ndlp->nlp_flag); + mp = mbox->ctx_buf; + if (mp) { + lpfc_mbuf_free(phba, mp->virt, + mp->phys); + kfree(mp); + } + mempool_free(mbox, phba->mbox_mem_pool); + goto out; } - mempool_free(mbox, phba->mbox_mem_pool); - goto out; } /* Increment reference count to ndlp to hold the * reference to ndlp for the callback function. */ mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) + goto out; + mbox->vport = vport; if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) { mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; @@ -4657,12 +4652,12 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, mempool_free(mbox, phba->mbox_mem_pool); } out: - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && shost) { - spin_lock_irq(shost->host_lock); + if (ndlp && shost) { + spin_lock_irq(&ndlp->lock); if (mbox) ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN; ndlp->nlp_flag &= ~NLP_RM_DFLT_RPI; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* If the node is not being used by another discovery thread, * and we are sending a reject, we are done with it. @@ -4676,10 +4671,11 @@ out: * the routine lpfc_els_free_iocb. */ cmdiocb->context1 = NULL; - } + /* Release the originating I/O reference. */ lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -4713,7 +4709,6 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; IOCB_t *icmd; IOCB_t *oldcmd; @@ -4732,9 +4727,9 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, ndlp->nlp_DID, ELS_CMD_ACC); if (!elsiocb) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return 1; } @@ -4838,23 +4833,40 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, return 1; } if (ndlp->nlp_flag & NLP_LOGO_ACC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED || ndlp->nlp_flag & NLP_REG_LOGIN_SEND)) ndlp->nlp_flag &= ~NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc; } else { elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; } phba->fc_stat.elsXmitACC++; + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + if (rc == IOCB_ERROR) + goto io_err; + + /* Xmit ELS ACC response tag <ulpIoTag> */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, " + "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " + "RPI: x%x, fc_flag x%x\n", + rc, elsiocb->iotag, elsiocb->sli4_xritag, + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_rpi, vport->fc_flag); return 0; + +io_err: + lpfc_nlp_put(ndlp); +node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -4884,13 +4896,13 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox) { + int rc; struct lpfc_hba *phba = vport->phba; IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; - int rc; cmdsize = 2 * sizeof(uint32_t); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, @@ -4925,13 +4937,21 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, phba->fc_stat.elsXmitLSRJT++; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + goto io_err; - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -4995,16 +5015,18 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, ap->DID = be32_to_cpu(vport->fc_myDID); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC ADISC: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); + "Issue ACC ADISC: did:x%x flg:x%x refcnt %d", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + if (rc == IOCB_ERROR) + goto io_err; /* Xmit ELS ACC response tag <ulpIoTag> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -5015,6 +5037,12 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi, vport->fc_flag); return 0; + +io_err: + lpfc_nlp_put(ndlp); +node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -5162,18 +5190,25 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, ndlp->nlp_DID); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC PRLI: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); + "Issue ACC PRLI: did:x%x flg:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + if (rc == IOCB_ERROR) + goto io_err; return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -5262,18 +5297,26 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC RNID: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); + "Issue ACC RNID: did:x%x flg:x%x refcnt %d", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + if (rc == IOCB_ERROR) + goto io_err; + return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -5369,18 +5412,25 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, memcpy(pcmd, data, cmdsize - sizeof(uint32_t)); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC ECHO: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); + "Issue ACC ECHO: did:x%x flg:x%x refcnt %d", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + if (rc == IOCB_ERROR) + goto io_err; return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -5411,14 +5461,12 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport) /* go thru NPR nodes and issue any remaining ELS ADISCs */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_NPR_NODE && (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); lpfc_issue_els_adisc(vport, ndlp, 0); @@ -5469,8 +5517,6 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) /* go thru NPR nodes and issue any remaining ELS PLOGIs */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_NPR_NODE && (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 && @@ -5947,7 +5993,6 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, lpfc_max_els_tries, rdp_context->ndlp, rdp_context->ndlp->nlp_DID, ELS_CMD_ACC); - lpfc_nlp_put(ndlp); if (!elsiocb) goto free_rdp_context; @@ -6021,18 +6066,24 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, bpl->tus.w = le32_to_cpu(bpl->tus.w); phba->fc_stat.elsXmitACC++; + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) { + lpfc_els_free_iocb(phba, elsiocb); + goto free_rdp_context; + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) + if (rc == IOCB_ERROR) { + lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, elsiocb); + } - kfree(rdp_context); + goto free_rdp_context; - return; error: cmdsize = 2 * sizeof(uint32_t); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, lpfc_max_els_tries, ndlp, ndlp->nlp_DID, ELS_CMD_LS_RJT); - lpfc_nlp_put(ndlp); if (!elsiocb) goto free_rdp_context; @@ -6047,11 +6098,23 @@ error: phba->fc_stat.elsXmitLSRJT++; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) { + lpfc_els_free_iocb(phba, elsiocb); + goto free_rdp_context; + } - if (rc == IOCB_ERROR) + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, elsiocb); + } + free_rdp_context: + /* This reference put is for the original unsolicited RDP. If the + * iocb prep failed, there is no reference to remove. + */ + lpfc_nlp_put(ndlp); kfree(rdp_context); } @@ -6155,6 +6218,11 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, cmd = &cmdiocb->iocb; rdp_context->ndlp = lpfc_nlp_get(ndlp); + if (!rdp_context->ndlp) { + kfree(rdp_context); + rjt_err = LSRJT_UNABLE_TPC; + goto error; + } rdp_context->ox_id = cmd->unsli3.rcvsli3.ox_id; rdp_context->rx_id = cmd->ulpContext; rdp_context->cmpl = lpfc_els_rdp_cmpl; @@ -6249,10 +6317,19 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lcb_res->lcb_duration = lcb_context->duration; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; + + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) - lpfc_els_free_iocb(phba, elsiocb); + if (!rc) + goto out; + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); + out: kfree(lcb_context); return; @@ -6279,9 +6356,17 @@ error: elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitLSRJT++; + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) { + lpfc_els_free_iocb(phba, elsiocb); + goto free_lcb_context; + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) + if (rc == IOCB_ERROR) { + lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, elsiocb); + } free_lcb_context: kfree(lcb_context); } @@ -6381,7 +6466,7 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, uint8_t *lp; struct fc_lcb_request_frame *beacon; struct lpfc_lcb_context *lcb_context; - uint8_t state, rjt_err; + u8 state, rjt_err = 0; struct ls_rjt stat; pcmd = (struct lpfc_dmabuf *)cmdiocb->context2; @@ -6427,15 +6512,22 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lcb_context->ox_id = cmdiocb->iocb.unsli3.rcvsli3.ox_id; lcb_context->rx_id = cmdiocb->iocb.ulpContext; lcb_context->ndlp = lpfc_nlp_get(ndlp); + if (!lcb_context->ndlp) { + rjt_err = LSRJT_UNABLE_TPC; + goto rjt_free; + } + if (lpfc_sli4_set_beacon(vport, lcb_context, state)) { lpfc_printf_vlog(ndlp->vport, KERN_ERR, LOG_TRACE_EVENT, "0193 failed to send mail box"); - kfree(lcb_context); lpfc_nlp_put(ndlp); rjt_err = LSRJT_UNABLE_TPC; - goto rjt; + goto rjt_free; } return 0; + +rjt_free: + kfree(lcb_context); rjt: memset(&stat, 0, sizeof(stat)); stat.un.b.lsRjtRsnCode = rjt_err; @@ -6578,8 +6670,7 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) /* Move all affected nodes by pending RSCNs to NPR state. */ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp) || - (ndlp->nlp_state == NLP_STE_UNUSED_NODE) || + if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) || !lpfc_rscn_payload_check(vport, ndlp->nlp_DID)) continue; @@ -6914,8 +7005,7 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) vport->num_disc_nodes = 0; ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { /* Good ndlp, issue CT Request to NameServer. Need to * know how many gidfts were issued. If none, then just * flush the RSCN. Otherwise, the outstanding requests @@ -6933,13 +7023,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) } else { /* Nameserver login in question. Revalidate. */ if (ndlp) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_PLOGI_ISSUE); - if (!ndlp) { - lpfc_els_flush_rscn(vport); - return 0; - } ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); } else { ndlp = lpfc_nlp_init(vport, NameServer_DID); if (!ndlp) { @@ -7283,6 +7368,7 @@ lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, static void lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { + int rc = 0; MAILBOX_t *mb; IOCB_t *icmd; struct RLS_RSP *rls_rsp; @@ -7344,8 +7430,19 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_rpi); elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) - lpfc_els_free_iocb(phba, elsiocb); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + goto io_err; + return; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); } /** @@ -7386,6 +7483,8 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) | cmdiocb->iocb.ulpContext)); /* rx_id */ mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) + goto node_err; mbox->vport = vport; mbox->mbox_cmpl = lpfc_els_rsp_rls_acc; if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) @@ -7396,6 +7495,7 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, * command. */ lpfc_nlp_put(ndlp); +node_err: mempool_free(mbox, phba->mbox_mem_pool); } reject_out: @@ -7433,6 +7533,7 @@ static int lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_nodelist *ndlp) { + int rc = 0; struct lpfc_hba *phba = vport->phba; struct ls_rjt stat; struct RTV_RSP *rtv_rsp; @@ -7482,8 +7583,17 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, rtv_rsp->ratov, rtv_rsp->edtov, rtv_rsp->qtov); elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) { + lpfc_els_free_iocb(phba, elsiocb); + return 0; + } + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, elsiocb); + } return 0; reject_out: @@ -7523,7 +7633,7 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (ndlp != rrq->ndlp) ndlp = rrq->ndlp; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) return 1; /* If ndlp is not NULL, we will bump the reference count on it */ @@ -7552,13 +7662,20 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, did, rrq->xritag, rrq->rxid); elsiocb->context_un.rrq = rrq; elsiocb->iocb_cmpl = lpfc_cmpl_els_rrq; - ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; - if (ret == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (ret == IOCB_ERROR) + goto io_err; return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -7611,6 +7728,7 @@ static int lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) { + int rc = 0; struct lpfc_hba *phba = vport->phba; IOCB_t *icmd, *oldcmd; RPL_RSP rpl_rsp; @@ -7652,12 +7770,20 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, ndlp->nlp_rpi); elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + goto io_err; return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -7994,7 +8120,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) else { struct lpfc_nodelist *ndlp; ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) + if (ndlp) remote_ID = ndlp->nlp_DID; } list_add_tail(&piocb->dlist, &abort_list); @@ -8011,7 +8137,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) remote_ID, cmd->ulpCommand, cmd->ulpIoTag); spin_lock_irq(&phba->hbalock); list_del_init(&piocb->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, piocb); + lpfc_sli_issue_abort_iotag(phba, pring, piocb, NULL); spin_unlock_irq(&phba->hbalock); } @@ -8111,7 +8237,7 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { spin_lock_irqsave(&phba->hbalock, iflags); list_del_init(&piocb->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, piocb); + lpfc_sli_issue_abort_iotag(phba, pring, piocb, NULL); spin_unlock_irqrestore(&phba->hbalock, iflags); } if (!list_empty(&abort_list)) @@ -8221,7 +8347,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, uint32_t *pcmd; ndlp = cmdiocbp->context1; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) return; if (rspiocbp->iocb.ulpStatus == IOSTAT_LS_RJT) { @@ -8447,7 +8573,6 @@ static void lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) { - struct Scsi_Host *shost; struct lpfc_nodelist *ndlp; struct ls_rjt stat; uint32_t *payload, payload_len; @@ -8497,20 +8622,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, newnode = 1; if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) ndlp->nlp_type |= NLP_FABRIC; - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto dropit; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - newnode = 1; - if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) - ndlp->nlp_type |= NLP_FABRIC; } else if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { - /* This is similar to the new node path */ - ndlp = lpfc_nlp_get(ndlp); - if (!ndlp) - goto dropit; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); newnode = 1; } @@ -8521,17 +8633,18 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * Do not process any unsolicited ELS commands * if the ndlp is in DEV_LOSS */ - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); if (ndlp->nlp_flag & NLP_IN_DEV_LOSS) { - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); if (newnode) lpfc_nlp_put(ndlp); goto dropit; } - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto dropit; elsiocb->vport = vport; if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) { @@ -8540,9 +8653,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* ELS command <elsCmd> received from NPORT <did> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0112 ELS command x%x received from NPORT x%x " - "Data: x%x x%x x%x x%x\n", - cmd, did, vport->port_state, vport->fc_flag, - vport->fc_myDID, vport->fc_prevDID); + "refcnt %d Data: x%x x%x x%x x%x\n", + cmd, did, kref_read(&ndlp->kref), vport->port_state, + vport->fc_flag, vport->fc_myDID, vport->fc_prevDID); /* reject till our FLOGI completes or PLOGI assigned DID via PT2PT */ if ((vport->port_state < LPFC_FABRIC_CFG_LINK) && @@ -8593,9 +8706,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_TARGET_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PLOGI); @@ -8622,7 +8735,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_els_rcv_flogi(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_LOGO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8664,7 +8778,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRSCN++; lpfc_els_rcv_rscn(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_ADISC: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8742,7 +8857,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvLIRR++; lpfc_els_rcv_lirr(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RLS: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8752,7 +8868,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRLS++; lpfc_els_rcv_rls(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RPL: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8762,7 +8879,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRPL++; lpfc_els_rcv_rpl(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RNID: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8772,7 +8890,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRNID++; lpfc_els_rcv_rnid(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RTV: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8781,7 +8900,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRTV++; lpfc_els_rcv_rtv(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RRQ: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8791,7 +8911,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRRQ++; lpfc_els_rcv_rrq(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_ECHO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8801,7 +8922,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvECHO++; lpfc_els_rcv_echo(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_REC: /* receive this due to exchange closed */ @@ -8832,7 +8954,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, "0115 Unknown ELS command x%x " "received from NPORT x%x\n", cmd, did); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; } @@ -8843,9 +8966,14 @@ lsrjt: stat.un.b.lsRjtRsnCode = rjt_err; stat.un.b.lsRjtRsnCodeExp = rjt_exp; lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp, - NULL); + NULL); + /* Remove the reference from above for new nodes. */ + if (newnode) + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); } + /* Release the reference on this elsiocb, not the ndlp. */ lpfc_nlp_put(elsiocb->context1); elsiocb->context1 = NULL; @@ -8987,13 +9115,9 @@ lpfc_start_fdmi(struct lpfc_vport *vport) return; } } - if (!NLP_CHK_NODE_ACT(ndlp)) - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE); - if (ndlp) { - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); - } + lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); + lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); } /** @@ -9023,9 +9147,9 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) spin_lock_irq(shost->host_lock); if (vport->fc_flag & FC_DISC_DELAYED) { spin_unlock_irq(shost->host_lock); - lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, - "3334 Delay fc port discovery for %d seconds\n", - phba->fc_ratov); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "3334 Delay fc port discovery for %d secs\n", + phba->fc_ratov); mod_timer(&vport->delayed_disc_tmo, jiffies + msecs_to_jiffies(1000 * phba->fc_ratov)); return; @@ -9045,19 +9169,8 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) "0251 NameServer login: no memory\n"); return; } - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) { - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - lpfc_disc_start(vport); - return; - } - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, - "0348 NameServer login: node freed\n"); - return; - } } + ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); @@ -9177,8 +9290,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_start_fdiscs(phba); lpfc_do_scr_ns_plogi(phba, vport); } - } else + } else { lpfc_do_scr_ns_plogi(phba, vport); + } } mbox_err_exit: /* Now, we decrement the ndlp reference count held for this @@ -9211,6 +9325,11 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, lpfc_reg_vpi(vport, mbox); mbox->vport = vport; mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) { + mempool_free(mbox, phba->mbox_mem_pool); + goto mbox_err_exit; + } + mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport; if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED) { @@ -9283,7 +9402,6 @@ void lpfc_retry_pport_discovery(struct lpfc_hba *phba) { struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; /* Cancel the all vports retry delay retry timers */ lpfc_cancel_all_vport_retry_delay_timer(phba); @@ -9293,11 +9411,10 @@ lpfc_retry_pport_discovery(struct lpfc_hba *phba) if (!ndlp) return; - shost = lpfc_shost_from_vport(phba->pport); mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; phba->pport->port_state = LPFC_FLOGI; return; @@ -9419,13 +9536,12 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ list_for_each_entry_safe(np, next_np, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp) || - (np->nlp_state != NLP_STE_NPR_NODE) || + if ((np->nlp_state != NLP_STE_NPR_NODE) || !(np->nlp_flag & NLP_NPR_ADISC)) continue; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); np->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_unreg_rpi(vport, np); } lpfc_cleanup_pending_mbox(vport); @@ -9448,6 +9564,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * to update the MAC address. */ lpfc_register_new_vport(phba, vport, ndlp); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); goto out; } @@ -9457,16 +9574,22 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_register_new_vport(phba, vport, ndlp); else lpfc_do_scr_ns_plogi(phba, vport); + + /* The FDISC completed successfully. Move the fabric ndlp to + * UNMAPPED state and register with the transport. + */ + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); goto out; + fdisc_failed: if (vport->fc_vport && (vport->fc_vport->vport_state != FC_VPORT_NO_FABRIC_RSCS)) lpfc_vport_set_state(vport, FC_VPORT_FAILED); /* Cancel discovery timer */ lpfc_can_disctmo(vport); - lpfc_nlp_put(ndlp); out: lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } /** @@ -9559,16 +9682,25 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "Issue FDISC: did:x%x", did, 0, 0); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto err_out; + rc = lpfc_issue_fabric_iocb(phba, elsiocb); if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, - "0256 Issue FDISC: Cannot send IOCB\n"); - return 1; + lpfc_nlp_put(ndlp); + goto err_out; } + lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING); return 0; + + err_out: + lpfc_els_free_iocb(phba, elsiocb); + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0256 Issue FDISC: Cannot send IOCB\n"); + return 1; } /** @@ -9600,18 +9732,14 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "LOGO npiv cmpl: status:x%x/x%x did:x%x", irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID); - lpfc_els_free_iocb(phba, cmdiocb); - vport->unreg_vpi_cmpl = VPORT_ERROR; - - /* Trigger the release of the ndlp after logo */ - lpfc_nlp_put(ndlp); - /* NPIV LOGO completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "2928 NPIV LOGO completes to NPort x%x " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%x x%x x%x x%x\n", ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, vport->num_disc_nodes); + irsp->ulpTimeout, vport->num_disc_nodes, + kref_read(&ndlp->kref), ndlp->nlp_flag, + ndlp->fc4_xpt_flags); if (irsp->ulpStatus == IOSTAT_SUCCESS) { spin_lock_irq(shost->host_lock); @@ -9620,6 +9748,11 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); } + + /* Safe to release resources now. */ + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); + vport->unreg_vpi_cmpl = VPORT_ERROR; } /** @@ -9641,7 +9774,7 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, int lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + int rc = 0; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; @@ -9667,18 +9800,25 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp->nlp_DID, ndlp->nlp_flag, 0); elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } + spin_unlock_irq(&ndlp->lock); + elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto node_err; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + goto io_err; return 0; + + io_err: + lpfc_nlp_put(ndlp); + node_err: + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_LOGO_SND; + spin_unlock_irq(&ndlp->lock); + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -9764,8 +9904,6 @@ repeat: goto repeat; } } - - return; } /** @@ -10046,8 +10184,10 @@ lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *vport) spin_lock(&phba->sli4_hba.sgl_list_lock); list_for_each_entry_safe(sglq_entry, sglq_next, &phba->sli4_hba.lpfc_abts_els_sgl_list, list) { - if (sglq_entry->ndlp && sglq_entry->ndlp->vport == vport) + if (sglq_entry->ndlp && sglq_entry->ndlp->vport == vport) { + lpfc_nlp_put(sglq_entry->ndlp); sglq_entry->ndlp = NULL; + } } spin_unlock(&phba->sli4_hba.sgl_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); @@ -10090,9 +10230,13 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, sglq_entry->state = SGL_FREED; spin_unlock(&phba->sli4_hba.sgl_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_set_rrq_active(phba, ndlp, - sglq_entry->sli4_lxritag, - rxid, 1); + + if (ndlp) { + lpfc_set_rrq_active(phba, ndlp, + sglq_entry->sli4_lxritag, + rxid, 1); + lpfc_nlp_put(ndlp); + } /* Check if TXQ queue needs to be serviced */ if (pring && !list_empty(&pring->txq)) @@ -10155,10 +10299,10 @@ lpfc_sli_abts_recover_port(struct lpfc_vport *vport, * The rport is not responding. Remove the FCP-2 flag to prevent * an ADISC in the follow-up recovery code. */ - spin_lock_irqsave(shost->host_lock, flags); + spin_lock_irqsave(&ndlp->lock, flags); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; ndlp->nlp_flag |= NLP_ISSUE_LOGO; - spin_unlock_irqrestore(shost->host_lock, flags); + spin_unlock_irqrestore(&ndlp->lock, flags); lpfc_unreg_rpi(vport, ndlp); } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index bb02fd8bc2dd..2b6b5fc671fe 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -73,34 +73,67 @@ static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); static int lpfc_fcf_inuse(struct lpfc_hba *); static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *); -void -lpfc_terminate_rport_io(struct fc_rport *rport) +/* The source of a terminate rport I/O is either a dev_loss_tmo + * event or a call to fc_remove_host. While the rport should be + * valid during these downcalls, the transport can call twice + * in a single event. This routine provides somoe protection + * as the NDLP isn't really free, just released to the pool. + */ +static int +lpfc_rport_invalid(struct fc_rport *rport) { struct lpfc_rport_data *rdata; - struct lpfc_nodelist * ndlp; - struct lpfc_hba *phba; + struct lpfc_nodelist *ndlp; + + if (!rport) { + pr_err("**** %s: NULL rport, exit.\n", __func__); + return -EINVAL; + } rdata = rport->dd_data; + if (!rdata) { + pr_err("**** %s: NULL dd_data on rport %p SID x%x\n", + __func__, rport, rport->scsi_target_id); + return -EINVAL; + } + ndlp = rdata->pnode; + if (!rdata->pnode) { + pr_err("**** %s: NULL ndlp on rport %p SID x%x\n", + __func__, rport, rport->scsi_target_id); + return -EINVAL; + } - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) - printk(KERN_ERR "Cannot find remote node" - " to terminate I/O Data x%x\n", - rport->port_id); - return; + if (!ndlp->vport) { + pr_err("**** %s: Null vport on ndlp %p, DID x%x rport %p " + "SID x%x\n", __func__, ndlp, ndlp->nlp_DID, rport, + rport->scsi_target_id); + return -EINVAL; } + return 0; +} + +void +lpfc_terminate_rport_io(struct fc_rport *rport) +{ + struct lpfc_rport_data *rdata; + struct lpfc_nodelist *ndlp; + struct lpfc_vport *vport; - phba = ndlp->phba; + if (lpfc_rport_invalid(rport)) + return; - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT, - "rport terminate: sid:x%x did:x%x flg:x%x", - ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); + rdata = rport->dd_data; + ndlp = rdata->pnode; + vport = ndlp->vport; + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, + "rport terminate: sid:x%x did:x%x flg:x%x", + ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); if (ndlp->nlp_sid != NLP_NO_SID) { - lpfc_sli_abort_iocb(ndlp->vport, - &phba->sli.sli3_ring[LPFC_FCP_RING], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); + lpfc_sli_abort_iocb(vport, + &vport->phba->sli.sli3_ring[LPFC_FCP_RING], + ndlp->nlp_sid, 0, LPFC_CTX_TGT); } } @@ -110,19 +143,14 @@ lpfc_terminate_rport_io(struct fc_rport *rport) void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) { - struct lpfc_rport_data *rdata; - struct lpfc_nodelist * ndlp; + struct lpfc_nodelist *ndlp; struct lpfc_vport *vport; - struct Scsi_Host *shost; struct lpfc_hba *phba; struct lpfc_work_evt *evtp; - int put_node; - int put_rport; unsigned long iflags; - rdata = rport->dd_data; - ndlp = rdata->pnode; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + ndlp = ((struct lpfc_rport_data *)rport->dd_data)->pnode; + if (!ndlp) return; vport = ndlp->vport; @@ -133,22 +161,24 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3181 dev_loss_callbk x%06x, rport x%px flg x%x\n", - ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag); + "3181 dev_loss_callbk x%06x, rport %p flg x%x " + "load_flag x%x refcnt %d\n", + ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag, + vport->load_flag, kref_read(&ndlp->kref)); - /* Don't defer this if we are in the process of deleting the vport - * or unloading the driver. The unload will cleanup the node - * appropriately we just need to cleanup the ndlp rport info here. + /* Don't schedule a worker thread event if the vport is going down. + * The teardown process cleans up the node via lpfc_drop_node. */ if (vport->load_flag & FC_UNLOADING) { - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; + ((struct lpfc_rport_data *)rport->dd_data)->pnode = NULL; ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); + + ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; + + /* Remove the node reference from remote_port_add now. + * The driver will not call remote_port_delete. + */ + lpfc_nlp_put(ndlp); return; } @@ -165,20 +195,28 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) if (!list_empty(&evtp->evt_listp)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, - "6790 rport name %llx dev_loss_evt pending", + "6790 rport name %llx dev_loss_evt pending\n", rport->port_name); return; } - shost = lpfc_shost_from_vport(vport); - spin_lock_irqsave(shost->host_lock, iflags); + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag |= NLP_IN_DEV_LOSS; - spin_unlock_irqrestore(shost->host_lock, iflags); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + + /* + * The backend does not expect any more calls associated with this + * rport. Remove the association between rport and ndlp. + */ + ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; + ((struct lpfc_rport_data *)rport->dd_data)->pnode = NULL; + ndlp->rport = NULL; + spin_unlock_irqrestore(&ndlp->lock, iflags); /* We need to hold the node by incrementing the reference * count until this queued work is done */ - evtp->evt_arg1 = lpfc_nlp_get(ndlp); + evtp->evt_arg1 = lpfc_nlp_get(ndlp); spin_lock_irqsave(&phba->hbalock, iflags); if (evtp->evt_arg1) { @@ -204,70 +242,34 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) static int lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) { - struct lpfc_rport_data *rdata; - struct fc_rport *rport; struct lpfc_vport *vport; struct lpfc_hba *phba; - struct Scsi_Host *shost; uint8_t *name; - int put_node; int warn_on = 0; int fcf_inuse = 0; unsigned long iflags; - rport = ndlp->rport; vport = ndlp->vport; - shost = lpfc_shost_from_vport(vport); + name = (uint8_t *)&ndlp->nlp_portname; + phba = vport->phba; - spin_lock_irqsave(shost->host_lock, iflags); + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; - spin_unlock_irqrestore(shost->host_lock, iflags); - - if (!rport) - return fcf_inuse; - - name = (uint8_t *) &ndlp->nlp_portname; - phba = vport->phba; + spin_unlock_irqrestore(&ndlp->lock, iflags); if (phba->sli_rev == LPFC_SLI_REV4) fcf_inuse = lpfc_fcf_inuse(phba); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport devlosstmo:did:x%x type:x%x id:x%x", - ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); + "rport devlosstmo:did:x%x type:x%x id:x%x", + ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_sid); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3182 dev_loss_tmo_handler x%06x, rport x%px flg x%x\n", - ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag); - - /* - * lpfc_nlp_remove if reached with dangling rport drops the - * reference. To make sure that does not happen clear rport - * pointer in ndlp before lpfc_nlp_put. - */ - rdata = rport->dd_data; - - /* Don't defer this if we are in the process of deleting the vport - * or unloading the driver. The unload will cleanup the node - * appropriately we just need to cleanup the ndlp rport info here. - */ - if (vport->load_flag & FC_UNLOADING) { - if (ndlp->nlp_sid != NLP_NO_SID) { - /* flush the target */ - lpfc_sli_abort_iocb(vport, - &phba->sli.sli3_ring[LPFC_FCP_RING], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); - } - put_node = rdata->pnode != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - put_device(&rport->dev); - - return fcf_inuse; - } + "3182 %s x%06x, nflag x%x xflags x%x refcnt %d\n", + __func__, ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->fc4_xpt_flags, kref_read(&ndlp->kref)); + /* If the driver is recovering the rport, ignore devloss. */ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0284 Devloss timeout Ignored on " @@ -279,15 +281,11 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) return fcf_inuse; } - put_node = rdata->pnode != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) + /* Fabric nodes are done. */ + if (ndlp->nlp_type & NLP_FABRIC) { lpfc_nlp_put(ndlp); - put_device(&rport->dev); - - if (ndlp->nlp_type & NLP_FABRIC) return fcf_inuse; + } if (ndlp->nlp_sid != NLP_NO_SID) { warn_on = 1; @@ -315,11 +313,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ndlp->nlp_state, ndlp->nlp_rpi); } - if (!(ndlp->nlp_flag & NLP_DELAY_TMO) && - !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) && - (ndlp->nlp_state != NLP_STE_PRLI_ISSUE)) + if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); return fcf_inuse; @@ -552,6 +546,15 @@ lpfc_work_list_done(struct lpfc_hba *phba) fcf_inuse, nlp_did); break; + case LPFC_EVT_RECOVER_PORT: + ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); + lpfc_sli_abts_recover_port(ndlp->vport, ndlp); + free_evt = 0; + /* decrement the node reference count held for + * this queued work + */ + lpfc_nlp_put(ndlp); + break; case LPFC_EVT_ONLINE: if (phba->link_state < LPFC_LINK_DOWN) *(int *) (evtp->evt_arg1) = lpfc_online(phba); @@ -811,13 +814,13 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) struct lpfc_nodelist *ndlp, *next_ndlp; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; + if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || - ((vport->port_type == LPFC_NPIV_PORT) && - (ndlp->nlp_DID == NameServer_DID))) + ((vport->port_type == LPFC_NPIV_PORT) && + ((ndlp->nlp_DID == NameServer_DID) || + (ndlp->nlp_DID == FDMI_DID)))) lpfc_unreg_rpi(vport, ndlp); /* Leave Fabric nodes alone on link down */ @@ -983,8 +986,7 @@ lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; if (ndlp->nlp_type & NLP_FABRIC) { @@ -1032,9 +1034,7 @@ lpfc_linkup_port(struct lpfc_vport *vport) vport->fc_ns_retry = 0; spin_unlock_irq(shost->host_lock); - if (vport->fc_flag & FC_LBIT) - lpfc_linkup_cleanup_nodes(vport); - + lpfc_linkup_cleanup_nodes(vport); } static int @@ -3196,7 +3196,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) } phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la); - phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED; + phba->link_flag &= ~(LS_NPIV_FAB_SUPPORTED | LS_CT_VEN_RPA); shost = lpfc_shost_from_vport(vport); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { @@ -3579,16 +3579,15 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_vport *vport = pmb->vport; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); pmb->ctx_buf = NULL; pmb->ctx_ndlp = NULL; - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "0002 rpi:%x DID:%x flg:%x %d map:%x x%px\n", + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI | LOG_NODE | LOG_DISCOVERY, + "0002 rpi:%x DID:%x flg:%x %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); + ndlp); if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; @@ -3602,9 +3601,9 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * there is another reg login in * process. */ - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* * We cannot leave the RPI registered because @@ -4076,8 +4075,16 @@ out: kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); - /* If no other thread is using the ndlp, free it */ - lpfc_nlp_not_used(ndlp); + /* If the node is not registered with the scsi or nvme + * transport, remove the fabric node. The failed reg_login + * is terminal. + */ + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(&ndlp->lock); + lpfc_nlp_not_used(ndlp); + } if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { /* @@ -4100,10 +4107,10 @@ out: ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, - "0003 rpi:%x DID:%x flg:%x %d map%x x%px\n", + "0003 rpi:%x DID:%x flg:%x %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); + ndlp); if (vport->port_state < LPFC_VPORT_READY) { /* Link up discovery requires Fabric registration. */ @@ -4124,7 +4131,9 @@ out: /* Issue SCR just before NameServer GID_FT Query */ lpfc_issue_els_scr(vport, 0); - lpfc_issue_els_rdf(vport, 0); + if (!phba->cfg_enable_mi || + phba->sli4_hba.pc_sli4_params.mi_ver < LPFC_MIB3_SUPPORT) + lpfc_issue_els_rdf(vport, 0); } vport->fc_ns_retry = 0; @@ -4154,6 +4163,7 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) struct lpfc_rport_data *rdata; struct fc_rport_identifiers rport_ids; struct lpfc_hba *phba = vport->phba; + unsigned long flags; if (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME) return; @@ -4164,47 +4174,46 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rport_ids.port_id = ndlp->nlp_DID; rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; - /* - * We leave our node pointer in rport->dd_data when we unregister a - * FCP target port. But fc_remote_port_add zeros the space to which - * rport->dd_data points. So, if we're reusing a previously - * registered port, drop the reference that we took the last time we - * registered the port. - */ - rport = ndlp->rport; - if (rport) { - rdata = rport->dd_data; - /* break the link before dropping the ref */ - ndlp->rport = NULL; - if (rdata) { - if (rdata->pnode == ndlp) - lpfc_nlp_put(ndlp); - rdata->pnode = NULL; - } - /* drop reference for earlier registeration */ - put_device(&rport->dev); - } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport add: did:x%x flg:x%x type x%x", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); + "rport add: did:x%x flg:x%x type x%x", + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); /* Don't add the remote port if unloading. */ if (vport->load_flag & FC_UNLOADING) return; + /* + * Disassociate any older association between this ndlp and rport + */ + if (ndlp->rport) { + rdata = ndlp->rport->dd_data; + rdata->pnode = NULL; + } + ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); - if (!rport || !get_device(&rport->dev)) { + if (!rport) { dev_printk(KERN_WARNING, &phba->pcidev->dev, "Warning: fc_remote_port_add failed\n"); return; } - /* initialize static port data */ + /* Successful port add. Complete initializing node data */ rport->maxframe_size = ndlp->nlp_maxframe; rport->supported_classes = ndlp->nlp_class_sup; rdata = rport->dd_data; rdata->pnode = lpfc_nlp_get(ndlp); + if (!rdata->pnode) { + dev_warn(&phba->pcidev->dev, + "Warning - node ref failed. Unreg rport\n"); + fc_remote_port_delete(rport); + ndlp->rport = NULL; + return; + } + + spin_lock_irqsave(&ndlp->lock, flags); + ndlp->fc4_xpt_flags |= SCSI_XPT_REGD; + spin_unlock_irqrestore(&ndlp->lock, flags); if (ndlp->nlp_type & NLP_FCP_TARGET) rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET; @@ -4221,13 +4230,14 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) fc_remote_port_rolechg(rport, rport_ids.roles); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3183 rport register x%06x, rport x%px role x%x\n", - ndlp->nlp_DID, rport, rport_ids.roles); + "3183 %s rport x%px DID x%x, role x%x\n", + __func__, rport, rport->port_id, rport->roles); if ((rport->scsi_target_id != -1) && (rport->scsi_target_id < LPFC_MAX_TARGET)) { ndlp->nlp_sid = rport->scsi_target_id; } + return; } @@ -4245,12 +4255,12 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "3184 rport unregister x%06x, rport x%px\n", - ndlp->nlp_DID, rport); + "3184 rport unregister x%06x, rport x%px " + "xptflg x%x\n", + ndlp->nlp_DID, rport, ndlp->fc4_xpt_flags); fc_remote_port_delete(rport); - - return; + lpfc_nlp_put(ndlp); } static void @@ -4296,8 +4306,6 @@ static void lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int old_state, int new_state) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (new_state == NLP_STE_UNMAPPED_NODE) { ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; ndlp->nlp_type |= NLP_FC_NODE; @@ -4391,9 +4399,9 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, (!ndlp->rport || ndlp->rport->scsi_target_id == -1 || ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_TGT_NO_SCSIID; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); } } @@ -4426,6 +4434,7 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); int old_state = ndlp->nlp_state; + int node_dropped = ndlp->nlp_flag & NLP_DROPPED; char name1[16], name2[16]; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, @@ -4438,6 +4447,12 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "node statechg did:x%x old:%d ste:%d", ndlp->nlp_DID, old_state, state); + if (node_dropped && old_state == NLP_STE_UNUSED_NODE && + state != NLP_STE_UNUSED_NODE) { + ndlp->nlp_flag &= ~NLP_DROPPED; + lpfc_nlp_get(ndlp); + } + if (old_state == NLP_STE_NPR_NODE && state != NLP_STE_NPR_NODE) lpfc_cancel_retry_delay_tmo(vport, ndlp); @@ -4485,15 +4500,6 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) NLP_STE_UNUSED_NODE); } -static void -lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - lpfc_cancel_retry_delay_tmo(vport, ndlp); - if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) - lpfc_nlp_counters(vport, ndlp->nlp_state, -1); - lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, - NLP_STE_UNUSED_NODE); -} /** * lpfc_initialize_node - Initialize all fields of node object * @vport: Pointer to Virtual Port object. @@ -4515,128 +4521,19 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); timer_setup(&ndlp->nlp_delayfunc, lpfc_els_retry_delay, 0); + INIT_LIST_HEAD(&ndlp->recovery_evt.evt_listp); + ndlp->nlp_DID = did; ndlp->vport = vport; ndlp->phba = vport->phba; ndlp->nlp_sid = NLP_NO_SID; ndlp->nlp_fc4_type = NLP_FC4_NONE; kref_init(&ndlp->kref); - NLP_INT_NODE_ACT(ndlp); atomic_set(&ndlp->cmd_pending, 0); ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; } -struct lpfc_nodelist * -lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - int state) -{ - struct lpfc_hba *phba = vport->phba; - uint32_t did, flag; - unsigned long flags; - unsigned long *active_rrqs_xri_bitmap = NULL; - int rpi = LPFC_RPI_ALLOC_ERROR; - uint32_t defer_did = 0; - - if (!ndlp) - return NULL; - - if (phba->sli_rev == LPFC_SLI_REV4) { - if (ndlp->nlp_rpi == LPFC_RPI_ALLOC_ERROR) - rpi = lpfc_sli4_alloc_rpi(vport->phba); - else - rpi = ndlp->nlp_rpi; - - if (rpi == LPFC_RPI_ALLOC_ERROR) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0359 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d FAILED RPI " - " ALLOC\n", - __func__, - (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - return NULL; - } - } - - spin_lock_irqsave(&phba->ndlp_lock, flags); - /* The ndlp should not be in memory free mode */ - if (NLP_CHK_FREE_REQ(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0277 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - goto free_rpi; - } - /* The ndlp should not already be in active mode */ - if (NLP_CHK_NODE_ACT(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0278 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - goto free_rpi; - } - - /* First preserve the orginal DID, xri_bitmap and some flags */ - did = ndlp->nlp_DID; - flag = (ndlp->nlp_flag & NLP_UNREG_INP); - if (flag & NLP_UNREG_INP) - defer_did = ndlp->nlp_defer_did; - if (phba->sli_rev == LPFC_SLI_REV4) - active_rrqs_xri_bitmap = ndlp->active_rrqs_xri_bitmap; - - /* Zero ndlp except of ndlp linked list pointer */ - memset((((char *)ndlp) + sizeof (struct list_head)), 0, - sizeof (struct lpfc_nodelist) - sizeof (struct list_head)); - - /* Next reinitialize and restore saved objects */ - lpfc_initialize_node(vport, ndlp, did); - ndlp->nlp_flag |= flag; - if (flag & NLP_UNREG_INP) - ndlp->nlp_defer_did = defer_did; - if (phba->sli_rev == LPFC_SLI_REV4) - ndlp->active_rrqs_xri_bitmap = active_rrqs_xri_bitmap; - - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - if (vport->phba->sli_rev == LPFC_SLI_REV4) { - ndlp->nlp_rpi = rpi; - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0008 rpi:%x DID:%x flg:%x refcnt:%d " - "map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, - kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); - } - - - if (state != NLP_STE_UNUSED_NODE) - lpfc_nlp_set_state(vport, ndlp, state); - else - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0013 rpi:%x DID:%x flg:%x refcnt:%d " - "map:%x x%px STATE=UNUSED\n", - ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, - kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, - "node enable: did:x%x", - ndlp->nlp_DID, 0, 0); - return ndlp; - -free_rpi: - if (phba->sli_rev == LPFC_SLI_REV4) { - lpfc_sli4_free_rpi(vport->phba, rpi); - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - } - return NULL; -} - void lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { @@ -4650,6 +4547,7 @@ lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) return; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); + ndlp->nlp_flag |= NLP_DROPPED; if (vport->phba->sli_rev == LPFC_SLI_REV4) { lpfc_cleanup_vports_rrqs(vport, ndlp); lpfc_unreg_rpi(vport, ndlp); @@ -4908,8 +4806,14 @@ lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, { unsigned long iflags; + /* Driver always gets a reference on the mailbox job + * in support of async jobs. + */ + mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) + return; + if (ndlp->nlp_flag & NLP_ISSUE_LOGO) { - mbox->ctx_ndlp = ndlp; mbox->mbox_cmpl = lpfc_nlp_logo_unreg; } else if (phba->sli_rev == LPFC_SLI_REV4 && @@ -4917,20 +4821,15 @@ lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= LPFC_SLI_INTF_IF_TYPE_2) && (kref_read(&ndlp->kref) > 0)) { - mbox->ctx_ndlp = lpfc_nlp_get(ndlp); mbox->mbox_cmpl = lpfc_sli4_unreg_rpi_cmpl_clr; } else { if (vport->load_flag & FC_UNLOADING) { if (phba->sli_rev == LPFC_SLI_REV4) { - spin_lock_irqsave(&vport->phba->ndlp_lock, - iflags); + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag |= NLP_RELEASE_RPI; - spin_unlock_irqrestore(&vport->phba->ndlp_lock, - iflags); + spin_unlock_irqrestore(&ndlp->lock, iflags); } - lpfc_nlp_get(ndlp); } - mbox->ctx_ndlp = ndlp; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; } } @@ -4988,6 +4887,11 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_unreg_login(phba, vport->vpi, rpi, mbox); mbox->vport = vport; lpfc_set_unreg_login_mbx_cmpl(phba, vport, ndlp, mbox); + if (!mbox->ctx_ndlp) { + mempool_free(mbox, phba->mbox_mem_pool); + return 1; + } + if (mbox->mbox_cmpl == lpfc_sli4_unreg_rpi_cmpl_clr) /* * accept PLOGIs after unreg_rpi_cmpl @@ -5011,6 +4915,29 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) mempool_free(mbox, phba->mbox_mem_pool); acc_plogi = 1; } + } else { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "1444 Failed to allocate mempool " + "unreg_rpi UNREG x%x, " + "DID x%x, flag x%x, " + "ndlp x%px\n", + ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag, ndlp); + + /* Because mempool_alloc failed, we + * will issue a LOGO here and keep the rpi alive if + * not unloading. + */ + if (!(vport->load_flag & FC_UNLOADING)) { + ndlp->nlp_flag &= ~NLP_UNREG_INP; + lpfc_issue_els_logo(vport, ndlp, 0); + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(vport, ndlp, + NLP_STE_NPR_NODE); + } + + return 1; } lpfc_no_rpi(phba, ndlp); out: @@ -5131,11 +5058,9 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport) static int lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mb, *nextmb; struct lpfc_dmabuf *mp; - unsigned long iflags; /* Cleanup node for NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, @@ -5143,22 +5068,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "Data: x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - if (NLP_CHK_FREE_REQ(ndlp)) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0280 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - lpfc_dequeue_node(vport, ndlp); - } else { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0281 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - lpfc_disable_node(vport, ndlp); - } - + lpfc_dequeue_node(vport, ndlp); /* Don't need to clean up REG_LOGIN64 cmds for Default RPI cleanup */ @@ -5205,108 +5115,22 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_els_abort(phba, ndlp); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = 0; del_timer_sync(&ndlp->nlp_delayfunc); list_del_init(&ndlp->els_retry_evt.evt_listp); list_del_init(&ndlp->dev_loss_evt.evt_listp); + list_del_init(&ndlp->recovery_evt.evt_listp); lpfc_cleanup_vports_rrqs(vport, ndlp); if (phba->sli_rev == LPFC_SLI_REV4) ndlp->nlp_flag |= NLP_RELEASE_RPI; - if (!lpfc_unreg_rpi(vport, ndlp)) { - /* Clean up unregistered and non freed rpis */ - if ((ndlp->nlp_flag & NLP_RELEASE_RPI) && - !(ndlp->nlp_rpi == LPFC_RPI_ALLOC_ERROR)) { - lpfc_sli4_free_rpi(vport->phba, - ndlp->nlp_rpi); - spin_lock_irqsave(&vport->phba->ndlp_lock, - iflags); - ndlp->nlp_flag &= ~NLP_RELEASE_RPI; - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - spin_unlock_irqrestore(&vport->phba->ndlp_lock, - iflags); - } - } return 0; } -/* - * Check to see if we can free the nlp back to the freelist. - * If we are in the middle of using the nlp in the discovery state - * machine, defer the free till we reach the end of the state machine. - */ -static void -lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_rport_data *rdata; - struct fc_rport *rport; - LPFC_MBOXQ_t *mbox; - int rc; - - lpfc_cancel_retry_delay_tmo(vport, ndlp); - if ((ndlp->nlp_flag & NLP_DEFER_RM) && - !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) && - !(ndlp->nlp_flag & NLP_RPI_REGISTERED) && - phba->sli_rev != LPFC_SLI_REV4) { - /* For this case we need to cleanup the default rpi - * allocated by the firmware. - */ - lpfc_printf_vlog(vport, KERN_INFO, - LOG_NODE | LOG_DISCOVERY, - "0005 Cleanup Default rpi:x%x DID:x%x flg:x%x " - "ref %d map:x%x ndlp x%px\n", - ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); - if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) - != NULL) { - rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID, - (uint8_t *) &vport->fc_sparam, mbox, ndlp->nlp_rpi); - if (rc) { - mempool_free(mbox, phba->mbox_mem_pool); - } - else { - mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; - mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; - mbox->vport = vport; - mbox->ctx_ndlp = ndlp; - rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - } - } - } - } - lpfc_cleanup_node(vport, ndlp); - - /* - * ndlp->rport must be set to NULL before it reaches here - * i.e. break rport/node link before doing lpfc_nlp_put for - * registered rport and then drop the reference of rport. - */ - if (ndlp->rport) { - /* - * extra lpfc_nlp_put dropped the reference of ndlp - * for registered rport so need to cleanup rport - */ - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0940 removed node x%px DID x%x " - "rpi %d rport not null x%px\n", - ndlp, ndlp->nlp_DID, ndlp->nlp_rpi, - ndlp->rport); - rport = ndlp->rport; - rdata = rport->dd_data; - rdata->pnode = NULL; - ndlp->rport = NULL; - put_device(&rport->dev); - } -} - static int lpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t did) @@ -5373,8 +5197,8 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) if (lpfc_matchdid(vport, ndlp, did)) { data1 = (((uint32_t)ndlp->nlp_state << 24) | ((uint32_t)ndlp->nlp_xri << 16) | - ((uint32_t)ndlp->nlp_type << 8) | - ((uint32_t)ndlp->nlp_usg_map & 0xff)); + ((uint32_t)ndlp->nlp_type << 8) + ); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "0929 FIND node DID " "Data: x%px x%x x%x x%x x%x x%px\n", @@ -5442,7 +5266,6 @@ lpfc_findnode_mapped(struct lpfc_vport *vport) struct lpfc_nodelist * lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; ndlp = lpfc_findnode_did(vport, did); @@ -5463,28 +5286,9 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - return ndlp; - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - if (vport->phba->nvmet_support) - return NULL; - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE); - if (!ndlp) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI, - "0014 Could not enable ndlp\n"); - return NULL; - } - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "6454 Setup Enabled Node 2B_DISC x%x " - "Data:x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_flag, - ndlp->nlp_state, vport->fc_flag); - - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp; } @@ -5526,9 +5330,9 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6456 Skip Setup RSCN Node x%x " @@ -5562,9 +5366,9 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) */ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } return ndlp; } @@ -5802,7 +5606,7 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) icmd = &iocb->iocb; if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR || icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX) { - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); } } spin_unlock_irq(&phba->hbalock); @@ -5821,8 +5625,6 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { lpfc_free_tx(phba, ndlp); @@ -5910,8 +5712,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) /* Start discovery by sending FLOGI, clean up old rpis */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state != NLP_STE_NPR_NODE) continue; if (ndlp->nlp_type & NLP_FABRIC) { @@ -5963,7 +5763,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) "NameServer login\n"); /* Next look for NameServer ndlp */ ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) + if (ndlp) lpfc_els_abort(phba, ndlp); /* ReStart discovery */ @@ -6136,10 +5936,10 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, - "0004 rpi:%x DID:%x flg:%x %d map:%x x%px\n", + "0004 rpi:%x DID:%x flg:%x %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); + ndlp); /* * Start issuing Fabric-Device Management Interface (FDMI) command to * 0xfffffa (FDMI well known port). @@ -6168,10 +5968,6 @@ lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param) { uint16_t *rpi = param; - /* check for active node */ - if (!NLP_CHK_NODE_ACT(ndlp)) - return 0; - return ndlp->nlp_rpi == *rpi; } @@ -6320,16 +6116,17 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) memset(ndlp, 0, sizeof (struct lpfc_nodelist)); + spin_lock_init(&ndlp->lock); + lpfc_initialize_node(vport, ndlp, did); INIT_LIST_HEAD(&ndlp->nlp_listp); if (vport->phba->sli_rev == LPFC_SLI_REV4) { ndlp->nlp_rpi = rpi; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0007 Init New ndlp x%px, rpi:x%x DID:%x " - "flg:x%x refcnt:%d map:x%x\n", + "flg:x%x refcnt:%d\n", ndlp, ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, kref_read(&ndlp->kref), - ndlp->nlp_usg_map); + ndlp->nlp_flag, kref_read(&ndlp->kref)); ndlp->active_rrqs_xri_bitmap = mempool_alloc(vport->phba->active_rrq_pool, @@ -6354,39 +6151,37 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) static void lpfc_nlp_release(struct kref *kref) { - struct lpfc_hba *phba; - unsigned long flags; struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, kref); + struct lpfc_vport *vport = ndlp->vport; lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, "node release: did:x%x flg:x%x type:x%x", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0279 %s: ndlp:x%px did %x " - "usgmap:x%x refcnt:%d rpi:%x\n", - __func__, - (void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map, - kref_read(&ndlp->kref), ndlp->nlp_rpi); + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "0279 %s: ndlp:%p did %x refcnt:%d rpi:%x\n", + __func__, ndlp, ndlp->nlp_DID, + kref_read(&ndlp->kref), ndlp->nlp_rpi); /* remove ndlp from action. */ - lpfc_nlp_remove(ndlp->vport, ndlp); + lpfc_cancel_retry_delay_tmo(vport, ndlp); + lpfc_cleanup_node(vport, ndlp); - /* clear the ndlp active flag for all release cases */ - phba = ndlp->phba; - spin_lock_irqsave(&phba->ndlp_lock, flags); - NLP_CLR_NODE_ACT(ndlp); - spin_unlock_irqrestore(&phba->ndlp_lock, flags); + /* Clear Node key fields to give other threads notice + * that this node memory is not valid anymore. + */ + ndlp->vport = NULL; + ndlp->nlp_state = NLP_STE_FREED_NODE; + ndlp->nlp_flag = 0; + ndlp->fc4_xpt_flags = 0; /* free ndlp memory for final ndlp release */ - if (NLP_CHK_FREE_REQ(ndlp)) { - kfree(ndlp->lat_data); - if (phba->sli_rev == LPFC_SLI_REV4) - mempool_free(ndlp->active_rrqs_xri_bitmap, - ndlp->phba->active_rrq_pool); - mempool_free(ndlp, ndlp->phba->nlp_mem_pool); - } + kfree(ndlp->lat_data); + if (ndlp->phba->sli_rev == LPFC_SLI_REV4) + mempool_free(ndlp->active_rrqs_xri_bitmap, + ndlp->phba->active_rrq_pool); + mempool_free(ndlp, ndlp->phba->nlp_mem_pool); } /* This routine bumps the reference count for a ndlp structure to ensure @@ -6396,7 +6191,6 @@ lpfc_nlp_release(struct kref *kref) struct lpfc_nodelist * lpfc_nlp_get(struct lpfc_nodelist *ndlp) { - struct lpfc_hba *phba; unsigned long flags; if (ndlp) { @@ -6404,94 +6198,43 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) "node get: did:x%x flg:x%x refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); + /* The check of ndlp usage to prevent incrementing the * ndlp reference count that is in the process of being * released. */ - phba = ndlp->phba; - spin_lock_irqsave(&phba->ndlp_lock, flags); - if (!NLP_CHK_NODE_ACT(ndlp) || NLP_CHK_FREE_ACK(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); + spin_lock_irqsave(&ndlp->lock, flags); + if (!kref_get_unless_zero(&ndlp->kref)) { + spin_unlock_irqrestore(&ndlp->lock, flags); lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0276 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); + "0276 %s: ndlp:x%px refcnt:%d\n", + __func__, (void *)ndlp, kref_read(&ndlp->kref)); return NULL; - } else - kref_get(&ndlp->kref); - spin_unlock_irqrestore(&phba->ndlp_lock, flags); + } + spin_unlock_irqrestore(&ndlp->lock, flags); + } else { + WARN_ONCE(!ndlp, "**** %s, get ref on NULL ndlp!", __func__); } + return ndlp; } /* This routine decrements the reference count for a ndlp structure. If the - * count goes to 0, this indicates the the associated nodelist should be - * freed. Returning 1 indicates the ndlp resource has been released; on the - * other hand, returning 0 indicates the ndlp resource has not been released - * yet. + * count goes to 0, this indicates the associated nodelist should be freed. */ int lpfc_nlp_put(struct lpfc_nodelist *ndlp) { - struct lpfc_hba *phba; - unsigned long flags; - - if (!ndlp) - return 1; - - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node put: did:x%x flg:x%x refcnt:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, - kref_read(&ndlp->kref)); - phba = ndlp->phba; - spin_lock_irqsave(&phba->ndlp_lock, flags); - /* Check the ndlp memory free acknowledge flag to avoid the - * possible race condition that kref_put got invoked again - * after previous one has done ndlp memory free. - */ - if (NLP_CHK_FREE_ACK(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0274 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - return 1; - } - /* Check the ndlp inactivate log flag to avoid the possible - * race condition that kref_put got invoked again after ndlp - * is already in inactivating state. - */ - if (NLP_CHK_IACT_REQ(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0275 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, + if (ndlp) { + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node put: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); - return 1; + } else { + WARN_ONCE(!ndlp, "**** %s, put ref on NULL ndlp!", __func__); } - /* For last put, mark the ndlp usage flags to make sure no - * other kref_get and kref_put on the same ndlp shall get - * in between the process when the final kref_put has been - * invoked on this ndlp. - */ - if (kref_read(&ndlp->kref) == 1) { - /* Indicate ndlp is put to inactive state. */ - NLP_SET_IACT_REQ(ndlp); - /* Acknowledge ndlp memory free has been seen. */ - if (NLP_CHK_FREE_REQ(ndlp)) - NLP_SET_FREE_ACK(ndlp); - } - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - /* Note, the kref_put returns 1 when decrementing a reference - * count that was 1, it invokes the release callback function, - * but it still left the reference count as 1 (not actually - * performs the last decrementation). Otherwise, it actually - * decrements the reference count and returns 0. - */ - return kref_put(&ndlp->kref, lpfc_nlp_release); + + return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; } /* This routine free's the specified nodelist if it is not in use @@ -6551,7 +6294,7 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) goto out; } list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport && + if (ndlp->rport && (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { ret = 1; spin_unlock_irq(shost->host_lock); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index c20034b3101c..42682d95af52 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1380,6 +1380,9 @@ struct lpfc_fdmi_reg_hba { struct lpfc_fdmi_reg_port_list rpl; }; +/******** MI MIB ********/ +#define SLI_CT_MIB_Subtypes 0x11 + /* * Register HBA Attributes (RHAT) */ @@ -1465,7 +1468,7 @@ struct lpfc_fdmi_reg_portattr { #define LPFC_FDMI2_HBA_ATTR 0x0002efff /* - * Port Attrubute Types + * Port Attribute Types */ #define RPRT_SUPPORTED_FC4_TYPES 0x1 /* 32 byte binary array */ #define RPRT_SUPPORTED_SPEED 0x2 /* 32-bit unsigned int */ @@ -1483,6 +1486,7 @@ struct lpfc_fdmi_reg_portattr { #define RPRT_PORT_STATE 0x101 /* 32-bit unsigned int */ #define RPRT_DISC_PORT 0x102 /* 32-bit unsigned int */ #define RPRT_PORT_ID 0x103 /* 32-bit unsigned int */ +#define RPRT_VENDOR_MI 0xf047 /* vendor ascii string */ #define RPRT_SMART_SERVICE 0xf100 /* 4 to 256 byte ASCII string */ #define RPRT_SMART_GUID 0xf101 /* 8 byte WWNN + 8 byte WWPN */ #define RPRT_SMART_VERSION 0xf102 /* 4 to 256 byte ASCII string */ @@ -1515,6 +1519,7 @@ struct lpfc_fdmi_reg_portattr { #define LPFC_FDMI_SMART_ATTR_port_info 0x00100000 /* Vendor specific */ #define LPFC_FDMI_SMART_ATTR_qos 0x00200000 /* Vendor specific */ #define LPFC_FDMI_SMART_ATTR_security 0x00400000 /* Vendor specific */ +#define LPFC_FDMI_VENDOR_ATTR_mi 0x00800000 /* Vendor specific */ /* Bit mask for FDMI-1 defined PORT attributes */ #define LPFC_FDMI1_PORT_ATTR 0x0000003f diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 12e4e76233e6..541b9aef6bfe 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -3506,8 +3506,14 @@ struct lpfc_sli4_parameters { #define cfg_max_tow_xri_MASK 0x0000ffff #define cfg_max_tow_xri_WORD word20 - uint32_t word21; /* RESERVED */ - uint32_t word22; /* RESERVED */ + uint32_t word21; +#define cfg_mib_bde_cnt_SHIFT 16 +#define cfg_mib_bde_cnt_MASK 0x000000ff +#define cfg_mib_bde_cnt_WORD word21 +#define cfg_mi_ver_SHIFT 0 +#define cfg_mi_ver_MASK 0x0000ffff +#define cfg_mi_ver_WORD word21 + uint32_t mib_size; uint32_t word23; /* RESERVED */ uint32_t word24; @@ -4380,9 +4386,11 @@ struct wqe_common { #define wqe_ebde_cnt_SHIFT 0 #define wqe_ebde_cnt_MASK 0x0000000f #define wqe_ebde_cnt_WORD word10 -#define wqe_nvme_SHIFT 4 -#define wqe_nvme_MASK 0x00000001 -#define wqe_nvme_WORD word10 +#define wqe_xchg_SHIFT 4 +#define wqe_xchg_MASK 0x00000001 +#define wqe_xchg_WORD word10 +#define LPFC_SCSI_XCHG 0x0 +#define LPFC_NVME_XCHG 0x1 #define wqe_oas_SHIFT 6 #define wqe_oas_MASK 0x00000001 #define wqe_oas_WORD word10 @@ -4880,6 +4888,8 @@ struct lpfc_grp_hdr { #define NVME_READ_CMD 0x0 #define FCP_COMMAND_DATA_OUT 0x1 #define NVME_WRITE_CMD 0x1 +#define COMMAND_DATA_IN 0x0 +#define COMMAND_DATA_OUT 0x1 #define FCP_COMMAND_TRECEIVE 0x2 #define FCP_COMMAND_TRSP 0x3 #define FCP_COMMAND_TSEND 0x7 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index ca25e54bb782..ac67f420ec26 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2844,28 +2844,6 @@ lpfc_cleanup(struct lpfc_vport *vport) lpfc_port_link_failure(vport); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - continue; - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - /* Trigger the release of the ndlp memory */ - lpfc_nlp_put(ndlp); - continue; - } - spin_lock_irq(&phba->ndlp_lock); - if (NLP_CHK_FREE_REQ(ndlp)) { - /* The ndlp should not be in memory free mode already */ - spin_unlock_irq(&phba->ndlp_lock); - continue; - } else - /* Indicate request for freeing ndlp memory */ - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - if (vport->port_type != LPFC_PHYSICAL_PORT && ndlp->nlp_DID == Fabric_DID) { /* Just free up ndlp with Fabric_DID for vports */ @@ -2873,20 +2851,23 @@ lpfc_cleanup(struct lpfc_vport *vport) continue; } - /* take care of nodes in unused state before the state - * machine taking action. - */ - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + if (ndlp->nlp_DID == Fabric_Cntl_DID && + ndlp->nlp_state == NLP_STE_UNUSED_NODE) { lpfc_nlp_put(ndlp); continue; } - if (ndlp->nlp_type & NLP_FABRIC) + /* Fabric Ports not in UNMAPPED state are cleaned up in the + * DEVICE_RM event. + */ + if (ndlp->nlp_type & NLP_FABRIC && + ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RM); + if (!(ndlp->fc4_xpt_flags & (NVME_XPT_REGD|SCSI_XPT_REGD))) + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); } /* At this point, ALL ndlp's should be gone @@ -2901,12 +2882,13 @@ lpfc_cleanup(struct lpfc_vport *vport) list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { lpfc_printf_vlog(ndlp->vport, KERN_ERR, - LOG_TRACE_EVENT, - "0282 did:x%x ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - ndlp->nlp_DID, (void *)ndlp, - ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); + LOG_TRACE_EVENT, + "0282 did:x%x ndlp:x%px " + "refcnt:%d xflags x%x nflag x%x\n", + ndlp->nlp_DID, (void *)ndlp, + kref_read(&ndlp->kref), + ndlp->fc4_xpt_flags, + ndlp->nlp_flag); } break; } @@ -3080,7 +3062,6 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) struct lpfc_nodelist *ndlp, *next_ndlp; struct lpfc_vport **vports; int i, rpi; - unsigned long flags; if (phba->sli_rev != LPFC_SLI_REV4) return; @@ -3096,22 +3077,18 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; rpi = lpfc_sli4_alloc_rpi(phba); if (rpi == LPFC_RPI_ALLOC_ERROR) { - spin_lock_irqsave(&phba->ndlp_lock, flags); - NLP_CLR_NODE_ACT(ndlp); - spin_unlock_irqrestore(&phba->ndlp_lock, flags); + /* TODO print log? */ continue; } ndlp->nlp_rpi = rpi; lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0009 Assign RPI x%x to ndlp x%px " - "DID:x%06x flg:x%x map:x%x\n", + "DID:x%06x flg:x%x\n", ndlp->nlp_rpi, ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, ndlp->nlp_usg_map); + ndlp->nlp_flag); } } lpfc_destroy_vport_work_array(phba, vports); @@ -3510,8 +3487,7 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, nlp_listp) { - if ((!NLP_CHK_NODE_ACT(ndlp)) || - ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { /* Driver must assume RPI is invalid for * any unused or inactive node. */ @@ -3519,33 +3495,42 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) continue; } - if (ndlp->nlp_type & NLP_FABRIC) { - lpfc_disc_state_machine(vports[i], ndlp, - NULL, NLP_EVT_DEVICE_RECOVERY); - lpfc_disc_state_machine(vports[i], ndlp, - NULL, NLP_EVT_DEVICE_RM); - } - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* * Whenever an SLI4 port goes offline, free the * RPI. Get a new RPI when the adapter port * comes back online. */ if (phba->sli_rev == LPFC_SLI_REV4) { - lpfc_printf_vlog(ndlp->vport, KERN_INFO, + lpfc_printf_vlog(vports[i], KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0011 Free RPI x%x on " - "ndlp:x%px did x%x " - "usgmap:x%x\n", + "ndlp: %p did x%x\n", ndlp->nlp_rpi, ndlp, - ndlp->nlp_DID, - ndlp->nlp_usg_map); + ndlp->nlp_DID); lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; } lpfc_unreg_rpi(vports[i], ndlp); + + if (ndlp->nlp_type & NLP_FABRIC) { + lpfc_disc_state_machine(vports[i], ndlp, + NULL, NLP_EVT_DEVICE_RECOVERY); + + /* Don't remove the node unless the + * has been unregistered with the + * transport. If so, let dev_loss + * take care of the node. + */ + if (!(ndlp->fc4_xpt_flags & + (NVME_XPT_REGD | SCSI_XPT_REGD))) + lpfc_disc_state_machine + (vports[i], ndlp, + NULL, + NLP_EVT_DEVICE_RM); + } } } } @@ -4343,16 +4328,13 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) /* Seed physical port template */ memcpy(template, &lpfc_template, sizeof(*template)); - if (use_no_reset_hba) { + if (use_no_reset_hba) /* template is for a no reset SCSI Host */ - template->max_sectors = 0xffff; template->eh_host_reset_handler = NULL; - } /* Template for all vports this physical port creates */ memcpy(&phba->vport_template, &lpfc_template, sizeof(*template)); - phba->vport_template.max_sectors = 0xffff; phba->vport_template.shost_attrs = lpfc_vport_attrs; phba->vport_template.eh_bus_reset_handler = NULL; phba->vport_template.eh_host_reset_handler = NULL; @@ -5607,11 +5589,6 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) ndlp->nlp_type |= NLP_FABRIC; /* Put ndlp onto node list */ lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 0; } if ((phba->pport->port_state < LPFC_FLOGI) && (phba->pport->port_state != LPFC_VPORT_FAILED)) @@ -5667,7 +5644,6 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, int rc; struct lpfc_vport *vport; struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; int active_vlink_present; struct lpfc_vport **vports; int i; @@ -5848,10 +5824,9 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_FDISC; vport->port_state = LPFC_FDISC; } else { @@ -5958,18 +5933,21 @@ lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba, void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) { struct lpfc_cq_event *cq_event; + unsigned long iflags; /* First, declare the async event has been handled */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag &= ~ASYNC_EVENT; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); + /* Now, handle all the async events */ + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); while (!list_empty(&phba->sli4_hba.sp_asynce_work_queue)) { - /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); list_remove_head(&phba->sli4_hba.sp_asynce_work_queue, cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, + iflags); + /* Process the asynchronous event */ switch (bf_get(lpfc_trailer_code, &cq_event->cqe.mcqe_cmpl)) { case LPFC_TRAILER_CODE_LINK: @@ -6001,9 +5979,12 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) &cq_event->cqe.mcqe_cmpl)); break; } + /* Free the completion event processed to the free pool */ lpfc_sli4_cq_event_release(phba, cq_event); + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); } + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); } /** @@ -6295,9 +6276,6 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) atomic_set(&phba->dbg_log_dmping, 0); spin_lock_init(&phba->hbalock); - /* Initialize ndlp management spinlock */ - spin_lock_init(&phba->ndlp_lock); - /* Initialize port_list spinlock */ spin_lock_init(&phba->port_list_lock); INIT_LIST_HEAD(&phba->port_list); @@ -6630,6 +6608,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* This abort list used by worker thread */ spin_lock_init(&phba->sli4_hba.sgl_list_lock); spin_lock_init(&phba->sli4_hba.nvmet_io_wait_lock); + spin_lock_init(&phba->sli4_hba.asynce_list_lock); + spin_lock_init(&phba->sli4_hba.els_xri_abrt_list_lock); /* * Initialize driver internal slow-path work queues @@ -6641,8 +6621,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) INIT_LIST_HEAD(&phba->sli4_hba.sp_queue_event); /* Asynchronous event CQ Event work queue list */ INIT_LIST_HEAD(&phba->sli4_hba.sp_asynce_work_queue); - /* Fast-path XRI aborted CQ Event work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue); /* Slow-path XRI aborted CQ Event work queue list */ INIT_LIST_HEAD(&phba->sli4_hba.sp_els_xri_aborted_work_queue); /* Receive queue CQ Event work queue list */ @@ -7196,7 +7174,6 @@ lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) "1431 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } return 0; } @@ -10174,26 +10151,28 @@ lpfc_sli4_cq_event_release(struct lpfc_hba *phba, static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba) { - LIST_HEAD(cqelist); - struct lpfc_cq_event *cqe; + LIST_HEAD(cq_event_list); + struct lpfc_cq_event *cq_event; unsigned long iflags; /* Retrieve all the pending WCQEs from pending WCQE lists */ - spin_lock_irqsave(&phba->hbalock, iflags); - /* Pending FCP XRI abort events */ - list_splice_init(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue, - &cqelist); + /* Pending ELS XRI abort events */ + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); list_splice_init(&phba->sli4_hba.sp_els_xri_aborted_work_queue, - &cqelist); + &cq_event_list); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); + /* Pending asynnc events */ + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); list_splice_init(&phba->sli4_hba.sp_asynce_work_queue, - &cqelist); - spin_unlock_irqrestore(&phba->hbalock, iflags); + &cq_event_list); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); - while (!list_empty(&cqelist)) { - list_remove_head(&cqelist, cqe, struct lpfc_cq_event, list); - lpfc_sli4_cq_event_release(phba, cqe); + while (!list_empty(&cq_event_list)) { + list_remove_head(&cq_event_list, cq_event, + struct lpfc_cq_event, list); + lpfc_sli4_cq_event_release(phba, cq_event); } } @@ -12310,6 +12289,21 @@ fcponly: else phba->nsler = 0; + /* Save PB info for use during HBA setup */ + sli4_params->mi_ver = bf_get(cfg_mi_ver, mbx_sli4_parameters); + sli4_params->mib_bde_cnt = bf_get(cfg_mib_bde_cnt, mbx_sli4_parameters); + sli4_params->mib_size = mbx_sli4_parameters->mib_size; + sli4_params->mi_value = LPFC_DFLT_MIB_VAL; + + /* Next we check for Vendor MIB support */ + if (sli4_params->mi_ver && phba->cfg_enable_mi) + phba->cfg_fdmi_on = LPFC_FDMI_SUPPORT; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "6461 MIB attr %d enable %d FDMI %d buf %d:%d\n", + sli4_params->mi_ver, phba->cfg_enable_mi, + sli4_params->mi_value, sli4_params->mib_bde_cnt, + sli4_params->mib_size); return 0; } @@ -12515,10 +12509,11 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) } lpfc_destroy_vport_work_array(phba, vports); - /* Remove FC host and then SCSI host with the physical port */ + /* Remove FC host with the physical port */ fc_remove_host(shost); scsi_remove_host(shost); + /* Clean up all nodes, mailboxes and IOs. */ lpfc_cleanup(vport); /* @@ -12581,8 +12576,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) /** * lpfc_pci_suspend_one_s3 - PCI func to suspend SLI-3 device for power mgmnt - * @pdev: pointer to PCI device - * @msg: power management message + * @dev_d: pointer to device * * This routine is to be called from the kernel's PCI subsystem to support * system Power Management (PM) to device with SLI-3 interface spec. When @@ -12600,10 +12594,10 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg) +static int __maybe_unused +lpfc_pci_suspend_one_s3(struct device *dev_d) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev_d); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -12617,16 +12611,12 @@ lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg) /* Disable interrupt from device */ lpfc_sli_disable_intr(phba); - /* Save device state to PCI config space */ - pci_save_state(pdev); - pci_set_power_state(pdev, PCI_D3hot); - return 0; } /** * lpfc_pci_resume_one_s3 - PCI func to resume SLI-3 device for power mgmnt - * @pdev: pointer to PCI device + * @dev_d: pointer to device * * This routine is to be called from the kernel's PCI subsystem to support * system Power Management (PM) to device with SLI-3 interface spec. When PM @@ -12643,10 +12633,10 @@ lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_resume_one_s3(struct pci_dev *pdev) +static int __maybe_unused +lpfc_pci_resume_one_s3(struct device *dev_d) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev_d); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; uint32_t intr_mode; int error; @@ -12654,19 +12644,6 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0452 PCI device Power Management resume.\n"); - /* Restore device state from PCI config space */ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - /* - * As the new kernel behavior of pci_restore_state() API call clears - * device saved_state flag, need to save the restored state again. - */ - pci_save_state(pdev); - - if (pdev->is_busmaster) - pci_set_master(pdev); - /* Startup the kernel thread for this host adapter. */ phba->worker_thread = kthread_run(lpfc_do_work, phba, "lpfc_worker_%d", phba->brd_no); @@ -13358,7 +13335,6 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) vport->load_flag |= FC_UNLOADING; spin_unlock_irq(&phba->hbalock); - /* Free the HBA sysfs attributes */ lpfc_free_sysfs_attr(vport); /* Release all the vports against this physical port */ @@ -13371,7 +13347,7 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) } lpfc_destroy_vport_work_array(phba, vports); - /* Remove FC host and then SCSI host with the physical port */ + /* Remove FC host with the physical port */ fc_remove_host(shost); scsi_remove_host(shost); @@ -13423,8 +13399,7 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) /** * lpfc_pci_suspend_one_s4 - PCI func to suspend SLI-4 device for power mgmnt - * @pdev: pointer to PCI device - * @msg: power management message + * @dev_d: pointer to device * * This routine is called from the kernel's PCI subsystem to support system * Power Management (PM) to device with SLI-4 interface spec. When PM invokes @@ -13442,10 +13417,10 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) +static int __maybe_unused +lpfc_pci_suspend_one_s4(struct device *dev_d) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev_d); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -13460,16 +13435,12 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) lpfc_sli4_disable_intr(phba); lpfc_sli4_queue_destroy(phba); - /* Save device state to PCI config space */ - pci_save_state(pdev); - pci_set_power_state(pdev, PCI_D3hot); - return 0; } /** * lpfc_pci_resume_one_s4 - PCI func to resume SLI-4 device for power mgmnt - * @pdev: pointer to PCI device + * @dev_d: pointer to device * * This routine is called from the kernel's PCI subsystem to support system * Power Management (PM) to device with SLI-4 interface spac. When PM invokes @@ -13486,10 +13457,10 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_resume_one_s4(struct pci_dev *pdev) +static int __maybe_unused +lpfc_pci_resume_one_s4(struct device *dev_d) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev_d); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; uint32_t intr_mode; int error; @@ -13497,19 +13468,6 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0292 PCI device Power Management resume.\n"); - /* Restore device state from PCI config space */ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - /* - * As the new kernel behavior of pci_restore_state() API call clears - * device saved_state flag, need to save the restored state again. - */ - pci_save_state(pdev); - - if (pdev->is_busmaster) - pci_set_master(pdev); - /* Startup the kernel thread for this host adapter. */ phba->worker_thread = kthread_run(lpfc_do_work, phba, "lpfc_worker_%d", phba->brd_no); @@ -13825,8 +13783,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) /** * lpfc_pci_suspend_one - lpfc PCI func to suspend dev for power management - * @pdev: pointer to PCI device - * @msg: power management message + * @dev: pointer to device * * This routine is to be registered to the kernel's PCI subsystem to support * system Power Management (PM). When PM invokes this method, it dispatches @@ -13837,19 +13794,19 @@ lpfc_pci_remove_one(struct pci_dev *pdev) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) +static int __maybe_unused +lpfc_pci_suspend_one(struct device *dev) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; int rc = -ENODEV; switch (phba->pci_dev_grp) { case LPFC_PCI_DEV_LP: - rc = lpfc_pci_suspend_one_s3(pdev, msg); + rc = lpfc_pci_suspend_one_s3(dev); break; case LPFC_PCI_DEV_OC: - rc = lpfc_pci_suspend_one_s4(pdev, msg); + rc = lpfc_pci_suspend_one_s4(dev); break; default: lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -13862,7 +13819,7 @@ lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) /** * lpfc_pci_resume_one - lpfc PCI func to resume dev for power management - * @pdev: pointer to PCI device + * @dev: pointer to device * * This routine is to be registered to the kernel's PCI subsystem to support * system Power Management (PM). When PM invokes this method, it dispatches @@ -13873,19 +13830,19 @@ lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_resume_one(struct pci_dev *pdev) +static int __maybe_unused +lpfc_pci_resume_one(struct device *dev) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; int rc = -ENODEV; switch (phba->pci_dev_grp) { case LPFC_PCI_DEV_LP: - rc = lpfc_pci_resume_one_s3(pdev); + rc = lpfc_pci_resume_one_s3(dev); break; case LPFC_PCI_DEV_OC: - rc = lpfc_pci_resume_one_s4(pdev); + rc = lpfc_pci_resume_one_s4(dev); break; default: lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -14065,14 +14022,17 @@ static const struct pci_error_handlers lpfc_err_handler = { .resume = lpfc_io_resume, }; +static SIMPLE_DEV_PM_OPS(lpfc_pci_pm_ops_one, + lpfc_pci_suspend_one, + lpfc_pci_resume_one); + static struct pci_driver lpfc_driver = { .name = LPFC_DRIVER_NAME, .id_table = lpfc_id_table, .probe = lpfc_pci_probe_one, .remove = lpfc_pci_remove_one, .shutdown = lpfc_pci_remove_one, - .suspend = lpfc_pci_suspend_one, - .resume = lpfc_pci_resume_one, + .driver.pm = &lpfc_pci_pm_ops_one, .err_handler = &lpfc_err_handler, }; @@ -14124,7 +14084,7 @@ lpfc_init(void) fc_release_transport(lpfc_transport_template); goto unregister; } - lpfc_nvme_cmd_template(); + lpfc_wqe_cmd_template(); lpfc_nvmet_cmd_template(); /* Initialize in case vector mapping is needed */ diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 27ff67e9edae..be54fbf5146f 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -46,6 +46,7 @@ #define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */ #define LPFC_DEVICE_DATA_POOL_SIZE 64 /* max elements in device data pool */ #define LPFC_RRQ_POOL_SIZE 256 /* max elements in non-DMA pool */ +#define LPFC_MBX_POOL_SIZE 256 /* max elements in MBX non-DMA pool */ int lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) { @@ -111,8 +112,8 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) pool->current_count++; } - phba->mbox_mem_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE, - sizeof(LPFC_MBOXQ_t)); + phba->mbox_mem_pool = mempool_create_kmalloc_pool(LPFC_MBX_POOL_SIZE, + sizeof(LPFC_MBOXQ_t)); if (!phba->mbox_mem_pool) goto fail_free_mbuf_pool; @@ -588,8 +589,6 @@ lpfc_sli4_rb_free(struct lpfc_hba *phba, struct hbq_dmabuf *dmab) * Description: Allocates a DMA-mapped receive buffer from the lpfc_hrb_pool PCI * pool along a non-DMA-mapped container for it. * - * Notes: Not interrupt-safe. Must be called with no locks held. - * * Returns: * pointer to HBQ on success * NULL on failure @@ -599,7 +598,7 @@ lpfc_sli4_nvmet_alloc(struct lpfc_hba *phba) { struct rqb_dmabuf *dma_buf; - dma_buf = kzalloc(sizeof(struct rqb_dmabuf), GFP_KERNEL); + dma_buf = kzalloc(sizeof(*dma_buf), GFP_KERNEL); if (!dma_buf) return NULL; @@ -722,7 +721,6 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys); rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe); if (rc < 0) { - (rqbp->rqb_free_buffer)(phba, rqb_entry); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "6409 Cannot post to HRQ %d: %x %x %x " "DRQ %x %x\n", @@ -732,6 +730,7 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) rqb_entry->hrq->entry_count, rqb_entry->drq->host_index, rqb_entry->drq->hba_index); + (rqbp->rqb_free_buffer)(phba, rqb_entry); } else { list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list); rqbp->buffer_count++; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 92d6e7b98770..1ac855640fc5 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -247,7 +247,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) { spin_lock_irq(&phba->hbalock); list_del_init(&iocb->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); spin_unlock_irq(&phba->hbalock); } @@ -357,7 +357,6 @@ lpfc_defer_acc_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * Complete the unreg rpi mbx request, and update flags. * This will also restart any deferred events. */ - lpfc_nlp_get(ndlp); lpfc_sli4_unreg_rpi_cmpl_clr(phba, pmb); if (!piocb) { @@ -365,7 +364,7 @@ lpfc_defer_acc_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) "4578 PLOGI ACC fail\n"); if (mbox) mempool_free(mbox, phba->mbox_mem_pool); - goto out; + return; } rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, piocb, ndlp, mbox); @@ -376,15 +375,12 @@ lpfc_defer_acc_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mempool_free(mbox, phba->mbox_mem_pool); } kfree(piocb); -out: - lpfc_nlp_put(ndlp); } static int lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *cmdiocb) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; uint64_t nlp_portwwn = 0; @@ -588,7 +584,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, rpi = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; lpfc_unreg_login(phba, vport->vpi, rpi, link_mbox); link_mbox->vport = vport; - link_mbox->ctx_ndlp = ndlp; + link_mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!link_mbox->ctx_ndlp) + goto out; + link_mbox->mbox_cmpl = lpfc_defer_acc_rsp; if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && @@ -617,9 +616,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * command issued in lpfc_cmpl_els_acc(). */ login_mbox->vport = vport; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* * If there is an outstanding PLOGI issued, abort it before @@ -648,9 +647,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * this ELS request. The only way to do this is * to register, then unregister the RPI. */ - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_RM_DFLT_RPI; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD; stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, @@ -739,7 +738,6 @@ static int lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *cmdiocb) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *elsiocb; struct lpfc_dmabuf *pcmd; struct serv_parm *sp; @@ -821,9 +819,9 @@ out: /* 1 sec timeout */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); @@ -843,9 +841,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary * PLOGIs during LOGO storms from a device. */ - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); if (els_cmd == ELS_CMD_PRLO) lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); else @@ -890,9 +888,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_FDISC; vport->port_state = LPFC_FDISC; } else { @@ -908,9 +906,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Only try to re-login if this is NOT a Fabric Node */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; } @@ -918,9 +916,9 @@ out: ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* The driver has to wait until the ACC completes before it continues * processing the LOGO. The action will resume in * lpfc_cmpl_els_logo_acc routine. Since part of processing includes an @@ -1036,12 +1034,10 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, static uint32_t lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return 0; } @@ -1050,16 +1046,16 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (vport->cfg_use_adisc && ((vport->fc_flag & FC_RSCN_MODE) || ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && (ndlp->nlp_type & NLP_FCP_TARGET)))) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return 1; } } - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_unreg_rpi(vport, ndlp); return 0; } @@ -1104,7 +1100,11 @@ lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport, lpfc_unreg_login(phba, vport->vpi, rpi, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; pmb->vport = vport; - pmb->ctx_ndlp = ndlp; + pmb->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!pmb->ctx_ndlp) { + mempool_free(pmb, phba->mbox_mem_pool); + return; + } if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && (!(vport->fc_flag & FC_OFFLINE_MODE))) @@ -1192,12 +1192,11 @@ static uint32_t lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return ndlp->nlp_state; @@ -1258,9 +1257,9 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (lpfc_rcv_plogi(vport, ndlp, cmdiocb) && (ndlp->nlp_flag & NLP_NPR_2B_DISC) && (vport->num_disc_nodes)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* Check if there are more PLOGIs to be sent */ lpfc_more_plogi(vport); if (vport->num_disc_nodes == 0) { @@ -1310,7 +1309,6 @@ static uint32_t lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; @@ -1325,9 +1323,9 @@ lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Put ndlp in npr state set plogi timer for 1 sec */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); @@ -1342,7 +1340,6 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, uint32_t evt) { struct lpfc_hba *phba = vport->phba; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb, *rspiocb; struct lpfc_dmabuf *pcmd, *prsp, *mp; uint32_t *lp; @@ -1488,7 +1485,11 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ndlp->nlp_flag |= NLP_REG_LOGIN_SEND; mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; } + mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) + goto out; + mbox->vport = vport; if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) != MBX_NOT_FINISHED) { @@ -1537,9 +1538,6 @@ out: ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DEFER_RM; - spin_unlock_irq(shost->host_lock); return NLP_STE_FREED_NODE; } @@ -1573,12 +1571,10 @@ static uint32_t lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } else { /* software abort outstanding PLOGI */ @@ -1595,7 +1591,6 @@ lpfc_device_recov_plogi_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; /* Don't do anything that will mess up processing of the @@ -1609,9 +1604,9 @@ lpfc_device_recov_plogi_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } @@ -1620,7 +1615,6 @@ static uint32_t lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb; @@ -1631,9 +1625,9 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); if (vport->num_disc_nodes) lpfc_more_adisc(vport); } @@ -1704,7 +1698,6 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb, *rspiocb; IOCB_t *irsp; @@ -1722,9 +1715,9 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, /* 1 sec timeout */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name)); @@ -1766,12 +1759,10 @@ static uint32_t lpfc_device_rm_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } else { /* software abort outstanding ADISC */ @@ -1788,7 +1779,6 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; /* Don't do anything that will mess up processing of the @@ -1802,9 +1792,9 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -1907,7 +1897,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, /* software abort if any GID_FT is outstanding */ if (vport->cfg_enable_fc4_type != LPFC_ENABLE_FCP) { ns_ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ns_ndlp && NLP_CHK_NODE_ACT(ns_ndlp)) + if (ns_ndlp) lpfc_els_abort(phba, ns_ndlp); } @@ -1946,7 +1936,6 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; MAILBOX_t *mb = &pmb->u.mb; @@ -1973,9 +1962,9 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, /* Put ndlp in npr state set plogi timer for 1 sec */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; lpfc_issue_els_logo(vport, ndlp, 0); @@ -2058,12 +2047,10 @@ lpfc_device_rm_reglogin_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } else { lpfc_drop_node(vport, ndlp); @@ -2077,8 +2064,6 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - /* Don't do anything that will mess up processing of the * previous RSCN. */ @@ -2087,7 +2072,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); /* If we are a target we won't immediately transition into PRLI, * so if REG_LOGIN already completed we don't need to ignore it. @@ -2097,7 +2082,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, ndlp->nlp_flag |= NLP_IGNR_REG_CMPL; ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2168,7 +2153,6 @@ static uint32_t lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb, *rspiocb; struct lpfc_hba *phba = vport->phba; IOCB_t *irsp; @@ -2290,9 +2274,9 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, (vport->port_type == LPFC_NPIV_PORT) && vport->cfg_restrict_login) { out: - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_TARGET_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_issue_els_logo(vport, ndlp, 0); ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; @@ -2344,12 +2328,10 @@ static uint32_t lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } else { /* software abort outstanding PLOGI */ @@ -2383,7 +2365,6 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; /* Don't do anything that will mess up processing of the @@ -2397,9 +2378,9 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2436,12 +2417,11 @@ static uint32_t lpfc_rcv_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)arg; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return ndlp->nlp_state; } @@ -2478,13 +2458,11 @@ static uint32_t lpfc_cmpl_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - ndlp->nlp_prev_state = NLP_STE_LOGO_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2578,14 +2556,12 @@ lpfc_device_recov_unmap_node(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; @@ -2656,14 +2632,12 @@ lpfc_device_recov_mapped_node(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2672,7 +2646,6 @@ static uint32_t lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; /* Ignore PLOGI if we have an outstanding LOGO */ @@ -2680,9 +2653,9 @@ lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp->nlp_state; if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } else if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { /* send PLOGI immediately, move to PLOGI issue state */ if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { @@ -2698,7 +2671,6 @@ static uint32_t lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; struct ls_rjt stat; @@ -2709,10 +2681,10 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { if (ndlp->nlp_flag & NLP_NPR_ADISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); lpfc_issue_els_adisc(vport, ndlp, 0); } else { @@ -2766,27 +2738,26 @@ static uint32_t lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) { mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; } else { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } return ndlp->nlp_state; } @@ -2797,16 +2768,12 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_iocbq *cmdiocb, *rspiocb; IOCB_t *irsp; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; irsp = &rspiocb->iocb; if (irsp->ulpStatus) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DEFER_RM; - spin_unlock_irq(shost->host_lock); return NLP_STE_FREED_NODE; } return ndlp->nlp_state; @@ -2893,12 +2860,10 @@ static uint32_t lpfc_device_rm_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } lpfc_drop_node(vport, ndlp); @@ -2909,8 +2874,6 @@ static uint32_t lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - /* Don't do anything that will mess up processing of the * previous RSCN. */ @@ -2918,10 +2881,10 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp->nlp_state; lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 0c39ed50998c..1cb82fa6a60e 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -62,180 +62,9 @@ lpfc_release_nvme_buf(struct lpfc_hba *, struct lpfc_io_buf *); static struct nvme_fc_port_template lpfc_nvme_template; -static union lpfc_wqe128 lpfc_iread_cmd_template; -static union lpfc_wqe128 lpfc_iwrite_cmd_template; -static union lpfc_wqe128 lpfc_icmnd_cmd_template; - -/* Setup WQE templates for NVME IOs */ -void -lpfc_nvme_cmd_template(void) -{ - union lpfc_wqe128 *wqe; - - /* IREAD template */ - wqe = &lpfc_iread_cmd_template; - memset(wqe, 0, sizeof(union lpfc_wqe128)); - - /* Word 0, 1, 2 - BDE is variable */ - - /* Word 3 - cmd_buff_len, payload_offset_len is zero */ - - /* Word 4 - total_xfer_len is variable */ - - /* Word 5 - is zero */ - - /* Word 6 - ctxt_tag, xri_tag is variable */ - - /* Word 7 */ - bf_set(wqe_cmnd, &wqe->fcp_iread.wqe_com, CMD_FCP_IREAD64_WQE); - bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, PARM_READ_CHECK); - bf_set(wqe_class, &wqe->fcp_iread.wqe_com, CLASS3); - bf_set(wqe_ct, &wqe->fcp_iread.wqe_com, SLI4_CT_RPI); - - /* Word 8 - abort_tag is variable */ - - /* Word 9 - reqtag is variable */ - - /* Word 10 - dbde, wqes is variable */ - bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0); - bf_set(wqe_nvme, &wqe->fcp_iread.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); - bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4); - bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0); - bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1); - - /* Word 11 - pbde is variable */ - bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, NVME_READ_CMD); - bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 1); - - /* Word 12 - is zero */ - - /* Word 13, 14, 15 - PBDE is variable */ - - /* IWRITE template */ - wqe = &lpfc_iwrite_cmd_template; - memset(wqe, 0, sizeof(union lpfc_wqe128)); - - /* Word 0, 1, 2 - BDE is variable */ - - /* Word 3 - cmd_buff_len, payload_offset_len is zero */ - - /* Word 4 - total_xfer_len is variable */ - - /* Word 5 - initial_xfer_len is variable */ - - /* Word 6 - ctxt_tag, xri_tag is variable */ - - /* Word 7 */ - bf_set(wqe_cmnd, &wqe->fcp_iwrite.wqe_com, CMD_FCP_IWRITE64_WQE); - bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, PARM_READ_CHECK); - bf_set(wqe_class, &wqe->fcp_iwrite.wqe_com, CLASS3); - bf_set(wqe_ct, &wqe->fcp_iwrite.wqe_com, SLI4_CT_RPI); - - /* Word 8 - abort_tag is variable */ - - /* Word 9 - reqtag is variable */ - - /* Word 10 - dbde, wqes is variable */ - bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0); - bf_set(wqe_nvme, &wqe->fcp_iwrite.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4); - bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); - bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); - - /* Word 11 - pbde is variable */ - bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, NVME_WRITE_CMD); - bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 1); - - /* Word 12 - is zero */ - - /* Word 13, 14, 15 - PBDE is variable */ - - /* ICMND template */ - wqe = &lpfc_icmnd_cmd_template; - memset(wqe, 0, sizeof(union lpfc_wqe128)); - - /* Word 0, 1, 2 - BDE is variable */ - - /* Word 3 - payload_offset_len is variable */ - - /* Word 4, 5 - is zero */ - - /* Word 6 - ctxt_tag, xri_tag is variable */ - - /* Word 7 */ - bf_set(wqe_cmnd, &wqe->fcp_icmd.wqe_com, CMD_FCP_ICMND64_WQE); - bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0); - bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, CLASS3); - bf_set(wqe_ct, &wqe->fcp_icmd.wqe_com, SLI4_CT_RPI); - - /* Word 8 - abort_tag is variable */ - - /* Word 9 - reqtag is variable */ - - /* Word 10 - dbde, wqes is variable */ - bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_nvme, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_NONE); - bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE); - bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0); - bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1); - - /* Word 11 */ - bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, FCP_COMMAND); - bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0); - - /* Word 12, 13, 14, 15 - is zero */ -} - -/** - * lpfc_nvme_prep_abort_wqe - set up 'abort' work queue entry. - * @pwqeq: Pointer to command iocb. - * @xritag: Tag that uniqely identifies the local exchange resource. - * @opt: Option bits - - * bit 0 = inhibit sending abts on the link - * - * This function is called with hbalock held. - **/ -void -lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt) -{ - union lpfc_wqe128 *wqe = &pwqeq->wqe; - - /* WQEs are reused. Clear stale data and set key fields to - * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. - */ - memset(wqe, 0, sizeof(*wqe)); - - if (opt & INHIBIT_ABORT) - bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); - /* Abort specified xri tag, with the mask deliberately zeroed */ - bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); - - bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); - - /* Abort the IO associated with this outstanding exchange ID. */ - wqe->abort_cmd.wqe_com.abort_tag = xritag; - - /* iotag for the wqe completion. */ - bf_set(wqe_reqtag, &wqe->abort_cmd.wqe_com, pwqeq->iotag); - - bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); - - bf_set(wqe_cmd_type, &wqe->abort_cmd.wqe_com, OTHER_COMMAND); - bf_set(wqe_wqec, &wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_cqid, &wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); -} - /** * lpfc_nvme_create_queue - * @pnvme_lport: Transport localport that LS is to be issued from - * @lpfc_pnvme: Pointer to the driver's nvme instance data * @qidx: An cpu index used to affinitize IO queues and MSIX vectors. * @qsize: Size of the queue in bytes * @handle: An opaque driver handle used in follow-up calls. @@ -357,39 +186,47 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) struct lpfc_nvme_rport *rport = remoteport->private; struct lpfc_vport *vport; struct lpfc_nodelist *ndlp; + u32 fc4_xpt_flags; ndlp = rport->ndlp; - if (!ndlp) + if (!ndlp) { + pr_err("**** %s: NULL ndlp on rport %p remoteport %p\n", + __func__, rport, remoteport); goto rport_err; + } vport = ndlp->vport; - if (!vport) + if (!vport) { + pr_err("**** %s: Null vport on ndlp %p, ste x%x rport %p\n", + __func__, ndlp, ndlp->nlp_state, rport); goto rport_err; + } + + fc4_xpt_flags = NVME_XPT_REGD | SCSI_XPT_REGD; /* Remove this rport from the lport's list - memory is owned by the * transport. Remove the ndlp reference for the NVME transport before * calling state machine to remove the node. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6146 remoteport delete of remoteport x%px\n", + "6146 remoteport delete of remoteport %p\n", remoteport); - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); /* The register rebind might have occurred before the delete * downcall. Guard against this race. */ - if (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG) { - ndlp->nrport = NULL; - ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG; - spin_unlock_irq(&vport->phba->hbalock); + if (ndlp->fc4_xpt_flags & NLP_WAIT_FOR_UNREG) + ndlp->fc4_xpt_flags &= ~(NLP_WAIT_FOR_UNREG | NVME_XPT_REGD); - /* Remove original register reference. The host transport - * won't reference this rport/remoteport any further. - */ - lpfc_nlp_put(ndlp); - } else { - spin_unlock_irq(&vport->phba->hbalock); - } + spin_unlock_irq(&ndlp->lock); + + /* On a devloss timeout event, one more put is executed provided the + * NVME and SCSI rport unregister requests are complete. If the vport + * is unloading, this extra put is executed by lpfc_drop_node. + */ + if (!(ndlp->fc4_xpt_flags & fc4_xpt_flags)) + lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); rport_err: return; @@ -567,6 +404,13 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, /* Save for completion so we can release these resources */ genwqe->context1 = lpfc_nlp_get(ndlp); + if (!genwqe->context1) { + dev_warn(&phba->pcidev->dev, + "Warning: Failed node ref, not sending LS_REQ\n"); + lpfc_sli_release_iocbq(phba, genwqe); + return 1; + } + genwqe->context2 = (uint8_t *)pnvme_lsreq; /* Fill in payload, bp points to frame payload */ @@ -654,6 +498,7 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, "Data: x%x x%x rc x%x\n", ndlp->nlp_DID, genwqe->iotag, vport->port_state, rc); + lpfc_nlp_put(ndlp); lpfc_sli_release_iocbq(phba, genwqe); return 1; } @@ -695,7 +540,7 @@ __lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int ret; uint16_t ntype, nstate; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6051 NVMEx LS REQ: Bad NDLP x%px, Failing " "LS Req\n", @@ -787,7 +632,7 @@ __lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /** * lpfc_nvme_ls_req - Issue an NVME Link Service request * @pnvme_lport: Transport localport that LS is to be issued from. - * @nvme_rport: Transport remoteport that LS is to be sent to. + * @pnvme_rport: Transport remoteport that LS is to be sent to. * @pnvme_lsreq: the transport nvme_ls_req structure for the LS * * Driver registers this routine to handle any link service request @@ -881,7 +726,7 @@ __lpfc_nvme_ls_abort(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock(&pring->ring_lock); if (foundit) - lpfc_sli_issue_abort_iotag(phba, pring, wqe); + lpfc_sli_issue_abort_iotag(phba, pring, wqe, NULL); spin_unlock_irq(&phba->hbalock); if (foundit) @@ -940,7 +785,6 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, { struct lpfc_nvme_lport *lport; struct lpfc_vport *vport; - struct lpfc_hba *phba; struct lpfc_nodelist *ndlp; int ret; @@ -948,7 +792,6 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, if (unlikely(!lport)) return; vport = lport->vport; - phba = vport->phba; if (vport->load_flag & FC_UNLOADING) return; @@ -1134,7 +977,7 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, * transport is still transitioning. */ ndlp = lpfc_ncmd->ndlp; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6062 Ignoring NVME cmpl. No ndlp\n"); goto out_err; @@ -1292,7 +1135,7 @@ out_err: /** * lpfc_nvme_prep_io_cmd - Issue an NVME-over-FCP IO * @vport: pointer to a host virtual N_Port data structure - * @lpfcn_cmd: Pointer to lpfc scsi command + * @lpfc_ncmd: Pointer to lpfc scsi command * @pnode: pointer to a node-list data structure * @cstat: pointer to the control status structure * @@ -1316,9 +1159,6 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, union lpfc_wqe128 *wqe = &pwqeq->wqe; uint32_t req_len; - if (!NLP_CHK_NODE_ACT(pnode)) - return -EINVAL; - /* * There are three possibilities here - use scatter-gather segment, use * the single mapping, or neither. @@ -1390,6 +1230,9 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, /* Word 9 */ bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag); + /* Word 10 */ + bf_set(wqe_xchg, &wqe->fcp_iwrite.wqe_com, LPFC_NVME_XCHG); + /* Words 13 14 15 are for PBDE support */ pwqeq->vport = vport; @@ -1400,7 +1243,7 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, /** * lpfc_nvme_prep_io_dma - Issue an NVME-over-FCP IO * @vport: pointer to a host virtual N_Port data structure - * @lpfcn_cmd: Pointer to lpfc scsi command + * @lpfc_ncmd: Pointer to lpfc scsi command * * Driver registers this routine as it io request handler. This * routine issues an fcp WQE with data from the @lpfc_nvme_fcpreq @@ -1557,7 +1400,9 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, le32_to_cpu(first_data_sgl->sge_len); bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; bde->tus.w = cpu_to_le32(bde->tus.w); - /* wqe_pbde is 1 in template */ + + /* Word 11 */ + bf_set(wqe_pbde, &wqe->generic.wqe_com, 1); } else { memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); bf_set(wqe_pbde, &wqe->generic.wqe_com, 0); @@ -1582,16 +1427,14 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, /** * lpfc_nvme_fcp_io_submit - Issue an NVME-over-FCP IO - * @lpfc_pnvme: Pointer to the driver's nvme instance data - * @lpfc_nvme_lport: Pointer to the driver's local port data - * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq - * @lpfc_nvme_fcreq: IO request from nvme fc to driver. + * @pnvme_lport: Pointer to the driver's local port data + * @pnvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq * @hw_queue_handle: Driver-returned handle in lpfc_nvme_create_queue + * @pnvme_fcreq: IO request from nvme fc to driver. * * Driver registers this routine as it io request handler. This * routine issues an fcp WQE with data from the @lpfc_nvme_fcpreq - * data structure to the rport - indicated in @lpfc_nvme_rport. + * data structure to the rport indicated in @lpfc_nvme_rport. * * Return value : * 0 - Success @@ -1670,7 +1513,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, * transport is still transitioning. */ ndlp = rport->ndlp; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_NVME_IOERR, "6053 Busy IO, ndlp not ready: rport x%px " "ndlp x%px, DID x%06x\n", @@ -1688,7 +1531,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, "IO. State x%x, Type x%x Flg x%x\n", pnvme_rport->port_id, ndlp->nlp_state, ndlp->nlp_type, - ndlp->upcall_flags); + ndlp->fc4_xpt_flags); atomic_inc(&lport->xmt_fcp_bad_ndlp); ret = -EBUSY; goto out_fail; @@ -1839,7 +1682,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, * lpfc_nvme_abort_fcreq_cmpl - Complete an NVME FCP abort request. * @phba: Pointer to HBA context object * @cmdiocb: Pointer to command iocb object. - * @rspiocb: Pointer to response iocb object. + * @abts_cmpl: Pointer to wcqe complete object. * * This is the callback function for any NVME FCP IO that was aborted. * @@ -1865,11 +1708,10 @@ lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /** * lpfc_nvme_fcp_abort - Issue an NVME-over-FCP ABTS - * @lpfc_pnvme: Pointer to the driver's nvme instance data - * @lpfc_nvme_lport: Pointer to the driver's local port data - * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq - * @lpfc_nvme_fcreq: IO request from nvme fc to driver. + * @pnvme_lport: Pointer to the driver's local port data + * @pnvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq * @hw_queue_handle: Driver-returned handle in lpfc_nvme_create_queue + * @pnvme_fcreq: IO request from nvme fc to driver. * * Driver registers this routine as its nvme request io abort handler. This * routine issues an fcp Abort WQE with data from the @lpfc_nvme_fcpreq @@ -1890,7 +1732,6 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, struct lpfc_vport *vport; struct lpfc_hba *phba; struct lpfc_io_buf *lpfc_nbuf; - struct lpfc_iocbq *abts_buf; struct lpfc_iocbq *nvmereq_wqe; struct lpfc_nvme_fcpreq_priv *freqpriv; unsigned long flags; @@ -2001,42 +1842,23 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, goto out_unlock; } - abts_buf = __lpfc_sli_get_iocbq(phba); - if (!abts_buf) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, - "6136 No available abort wqes. Skipping " - "Abts req for nvme_fcreq x%px xri x%x\n", - pnvme_fcreq, nvmereq_wqe->sli4_xritag); - goto out_unlock; - } - - /* Ready - mark outstanding as aborted by driver. */ - nvmereq_wqe->iocb_flag |= LPFC_DRIVER_ABORTED; + ret_val = lpfc_sli4_issue_abort_iotag(phba, nvmereq_wqe, + lpfc_nvme_abort_fcreq_cmpl); - lpfc_nvme_prep_abort_wqe(abts_buf, nvmereq_wqe->sli4_xritag, 0); - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abts_buf->iocb_flag |= LPFC_IO_NVME; - abts_buf->hba_wqidx = nvmereq_wqe->hba_wqidx; - abts_buf->vport = vport; - abts_buf->wqe_cmpl = lpfc_nvme_abort_fcreq_cmpl; - ret_val = lpfc_sli4_issue_wqe(phba, lpfc_nbuf->hdwq, abts_buf); spin_unlock(&lpfc_nbuf->buf_lock); spin_unlock_irqrestore(&phba->hbalock, flags); - if (ret_val) { + if (ret_val != WQE_SUCCESS) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6137 Failed abts issue_wqe with status x%x " "for nvme_fcreq x%px.\n", ret_val, pnvme_fcreq); - lpfc_sli_release_iocbq(phba, abts_buf); return; } lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, "6138 Transport Abort NVME Request Issued for " - "ox_id x%x on reqtag x%x\n", - nvmereq_wqe->sli4_xritag, - abts_buf->iotag); + "ox_id x%x\n", + nvmereq_wqe->sli4_xritag); return; out_unlock: @@ -2072,9 +1894,8 @@ static struct nvme_fc_port_template lpfc_nvme_template = { .fcprqst_priv_sz = sizeof(struct lpfc_nvme_fcpreq_priv), }; -/** +/* * lpfc_get_nvme_buf - Get a nvme buffer from io_buf_list of the HBA - * @phba: The HBA for which this call is being executed. * * This routine removes a nvme buffer from head of @hdwq io_buf_list * and returns to caller. @@ -2174,7 +1995,7 @@ lpfc_release_nvme_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd) /** * lpfc_nvme_create_localport - Create/Bind an nvme localport instance. - * @pvport - the lpfc_vport instance requesting a localport. + * @vport - the lpfc_vport instance requesting a localport. * * This routine is invoked to create an nvme localport instance to bind * to the nvme_fc_transport. It is called once during driver load @@ -2280,6 +2101,8 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, int ret, i, pending = 0; struct lpfc_sli_ring *pring; struct lpfc_hba *phba = vport->phba; + struct lpfc_sli4_hdw_queue *qp; + int abts_scsi, abts_nvme; /* Host transport has to clean up and confirm requiring an indefinite * wait. Print a message if a 10 second wait expires and renew the @@ -2290,17 +2113,23 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, ret = wait_for_completion_timeout(lport_unreg_cmp, wait_tmo); if (unlikely(!ret)) { pending = 0; + abts_scsi = 0; + abts_nvme = 0; for (i = 0; i < phba->cfg_hdw_queue; i++) { - pring = phba->sli4_hba.hdwq[i].io_wq->pring; + qp = &phba->sli4_hba.hdwq[i]; + pring = qp->io_wq->pring; if (!pring) continue; - if (pring->txcmplq_cnt) - pending += pring->txcmplq_cnt; + pending += pring->txcmplq_cnt; + abts_scsi += qp->abts_scsi_io_bufs; + abts_nvme += qp->abts_nvme_io_bufs; } lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6176 Lport x%px Localport x%px wait " - "timed out. Pending %d. Renewing.\n", - lport, vport->localport, pending); + "timed out. Pending %d [%d:%d]. " + "Renewing.\n", + lport, vport->localport, pending, + abts_scsi, abts_nvme); continue; } break; @@ -2313,7 +2142,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, /** * lpfc_nvme_destroy_localport - Destroy lpfc_nvme bound to nvme transport. - * @pnvme: pointer to lpfc nvme data structure. + * @vport: pointer to a host virtual N_Port data structure * * This routine is invoked to destroy all lports bound to the phba. * The lport memory was allocated by the nvme fc transport and is @@ -2454,14 +2283,18 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) else rpinfo.dev_loss_tmo = vport->cfg_devloss_tmo; - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); oldrport = lpfc_ndlp_get_nrport(ndlp); if (oldrport) { prev_ndlp = oldrport->ndlp; - spin_unlock_irq(&vport->phba->hbalock); + spin_unlock_irq(&ndlp->lock); } else { - spin_unlock_irq(&vport->phba->hbalock); - lpfc_nlp_get(ndlp); + spin_unlock_irq(&ndlp->lock); + if (!lpfc_nlp_get(ndlp)) { + dev_warn(&vport->phba->pcidev->dev, + "Warning - No node ref - exit register\n"); + return 0; + } } ret = nvme_fc_register_remoteport(localport, &rpinfo, &remote_port); @@ -2473,9 +2306,10 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* Guard against an unregister/reregister * race that leaves the WAIT flag set. */ - spin_lock_irq(&vport->phba->hbalock); - ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG; - spin_unlock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); + ndlp->fc4_xpt_flags &= ~NLP_WAIT_FOR_UNREG; + ndlp->fc4_xpt_flags |= NVME_XPT_REGD; + spin_unlock_irq(&ndlp->lock); rport = remote_port->private; if (oldrport) { @@ -2483,10 +2317,10 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * before dropping the ndlp ref from * register. */ - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); ndlp->nrport = NULL; - ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG; - spin_unlock_irq(&vport->phba->hbalock); + ndlp->fc4_xpt_flags &= ~NLP_WAIT_FOR_UNREG; + spin_unlock_irq(&ndlp->lock); rport->ndlp = NULL; rport->remoteport = NULL; @@ -2495,8 +2329,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * reference would cause a premature cleanup. */ if (prev_ndlp && prev_ndlp != ndlp) { - if ((!NLP_CHK_NODE_ACT(prev_ndlp)) || - (!prev_ndlp->nrport)) + if (!prev_ndlp->nrport) lpfc_nlp_put(prev_ndlp); } } @@ -2505,9 +2338,9 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rport->remoteport = remote_port; rport->lport = lport; rport->ndlp = ndlp; - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); ndlp->nrport = rport; - spin_unlock_irq(&vport->phba->hbalock); + spin_unlock_irq(&ndlp->lock); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_NODE, "6022 Bind lport x%px to remoteport x%px " @@ -2532,7 +2365,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) #endif } -/** +/* * lpfc_nvme_rescan_port - Check to see if we should rescan this remoteport * * If the ndlp represents an NVME Target, that we are logged into, @@ -2546,11 +2379,11 @@ lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) struct lpfc_nvme_rport *nrport; struct nvme_fc_remote_port *remoteport = NULL; - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); nrport = lpfc_ndlp_get_nrport(ndlp); if (nrport) remoteport = nrport->remoteport; - spin_unlock_irq(&vport->phba->hbalock); + spin_unlock_irq(&ndlp->lock); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6170 Rescan NPort DID x%06x type x%x " @@ -2613,20 +2446,21 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!lport) goto input_err; - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) remoteport = rport->remoteport; - spin_unlock_irq(&vport->phba->hbalock); + spin_unlock_irq(&ndlp->lock); if (!remoteport) goto input_err; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6033 Unreg nvme remoteport x%px, portname x%llx, " - "port_id x%06x, portstate x%x port type x%x\n", + "port_id x%06x, portstate x%x port type x%x " + "refcnt %d\n", remoteport, remoteport->port_name, remoteport->port_id, remoteport->port_state, - ndlp->nlp_type); + ndlp->nlp_type, kref_read(&ndlp->kref)); /* Sanity check ndlp type. Only call for NVME ports. Don't * clear any rport state until the transport calls back. @@ -2636,7 +2470,9 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* No concern about the role change on the nvme remoteport. * The transport will update it. */ - ndlp->upcall_flags |= NLP_WAIT_FOR_UNREG; + spin_lock_irq(&vport->phba->hbalock); + ndlp->fc4_xpt_flags |= NLP_WAIT_FOR_UNREG; + spin_unlock_irq(&vport->phba->hbalock); /* Don't let the host nvme transport keep sending keep-alives * on this remoteport. Vport is unloading, no recovery. The @@ -2647,8 +2483,15 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) (void)nvme_fc_set_remoteport_devloss(remoteport, 0); ret = nvme_fc_unregister_remoteport(remoteport); + + /* The driver no longer knows if the nrport memory is valid. + * because the controller teardown process has begun and + * is asynchronous. Break the binding in the ndlp. Also + * remove the register ndlp reference to setup node release. + */ + ndlp->nrport = NULL; + lpfc_nlp_put(ndlp); if (ret != 0) { - lpfc_nlp_put(ndlp); lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6167 NVME unregister failed %d " "port_state x%x\n", diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h index 4a4c3f780e1f..69a5a844c69c 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.h +++ b/drivers/scsi/lpfc/lpfc_nvme.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -38,7 +38,7 @@ #define LPFC_NVME_INFO_MORE_STR "\nCould be more info...\n" #define lpfc_ndlp_get_nrport(ndlp) \ - ((!ndlp->nrport || (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG)) \ + ((!ndlp->nrport || (ndlp->fc4_xpt_flags & NLP_WAIT_FOR_UNREG)) \ ? NULL : ndlp->nrport) struct lpfc_nvme_qhandle { diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index d4ade7cdb93a..a71df8788fff 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channsel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -105,7 +105,7 @@ lpfc_nvmet_cmd_template(void) /* Word 9 - reqtag, rcvoxid is variable */ /* Word 10 - wqes, xc is variable */ - bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1); + bf_set(wqe_xchg, &wqe->fcp_tsend.wqe_com, LPFC_NVME_XCHG); bf_set(wqe_dbde, &wqe->fcp_tsend.wqe_com, 1); bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0); bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1); @@ -153,7 +153,7 @@ lpfc_nvmet_cmd_template(void) /* Word 10 - xc is variable */ bf_set(wqe_dbde, &wqe->fcp_treceive.wqe_com, 1); bf_set(wqe_wqes, &wqe->fcp_treceive.wqe_com, 0); - bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1); + bf_set(wqe_xchg, &wqe->fcp_treceive.wqe_com, LPFC_NVME_XCHG); bf_set(wqe_iod, &wqe->fcp_treceive.wqe_com, LPFC_WQE_IOD_READ); bf_set(wqe_lenloc, &wqe->fcp_treceive.wqe_com, LPFC_WQE_LENLOC_WORD12); bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1); @@ -195,7 +195,7 @@ lpfc_nvmet_cmd_template(void) /* Word 10 wqes, xc is variable */ bf_set(wqe_dbde, &wqe->fcp_trsp.wqe_com, 1); - bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1); + bf_set(wqe_xchg, &wqe->fcp_trsp.wqe_com, LPFC_NVME_XCHG); bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 0); bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, 0); bf_set(wqe_iod, &wqe->fcp_trsp.wqe_com, LPFC_WQE_IOD_NONE); @@ -371,8 +371,7 @@ finish: /** * lpfc_nvmet_ctxbuf_post - Repost a NVMET RQ DMA buffer and clean up context * @phba: HBA buffer is associated with - * @ctxp: context to clean up - * @mp: Buffer to free + * @ctx_buf: ctx buffer context * * Description: Frees the given DMA buffer in the appropriate way given by * reposting it to its associated RQ so it can be reused. @@ -1291,10 +1290,10 @@ lpfc_nvmet_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, /** * lpfc_nvmet_ls_req - Issue an Link Service request - * @targetport - pointer to target instance registered with nvmet transport. - * @hosthandle - hosthandle set by the driver in a prior ls_rqst_rcv. + * @targetport: pointer to target instance registered with nvmet transport. + * @hosthandle: hosthandle set by the driver in a prior ls_rqst_rcv. * Driver sets this value to the ndlp pointer. - * @pnvme_lsreq - the transport nvme_ls_req structure for the LS + * @pnvme_lsreq: the transport nvme_ls_req structure for the LS * * Driver registers this routine to handle any link service request * from the nvme_fc transport to a remote nvme-aware port. @@ -1336,9 +1335,9 @@ lpfc_nvmet_ls_req(struct nvmet_fc_target_port *targetport, /** * lpfc_nvmet_ls_abort - Abort a prior NVME LS request * @targetport: Transport targetport, that LS was issued from. - * @hosthandle - hosthandle set by the driver in a prior ls_rqst_rcv. + * @hosthandle: hosthandle set by the driver in a prior ls_rqst_rcv. * Driver sets this value to the ndlp pointer. - * @pnvme_lsreq - the transport nvme_ls_req structure for LS to be aborted + * @pnvme_lsreq: the transport nvme_ls_req structure for LS to be aborted * * Driver registers this routine to abort an NVME LS request that is * in progress (from the transports perspective). @@ -1807,7 +1806,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, rrq_empty = list_empty(&phba->active_rrq_list); spin_unlock_irqrestore(&phba->hbalock, iflag); ndlp = lpfc_findnode_did(phba->pport, ctxp->sid); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + if (ndlp && (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE || ndlp->nlp_state == NLP_STE_MAPPED_NODE)) { lpfc_set_rrq_active(phba, ndlp, @@ -2597,7 +2596,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, } ndlp = lpfc_findnode_did(phba->pport, ctxp->sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -2717,7 +2716,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, } ndlp = lpfc_findnode_did(phba->pport, ctxp->sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, @@ -3249,7 +3248,7 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; ndlp = lpfc_findnode_did(phba->pport, sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { if (tgtp) @@ -3328,6 +3327,46 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, return 1; } +/** + * lpfc_nvmet_prep_abort_wqe - set up 'abort' work queue entry. + * @pwqeq: Pointer to command iocb. + * @xritag: Tag that uniqely identifies the local exchange resource. + * @opt: Option bits - + * bit 0 = inhibit sending abts on the link + * + * This function is called with hbalock held. + **/ +static void +lpfc_nvmet_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt) +{ + union lpfc_wqe128 *wqe = &pwqeq->wqe; + + /* WQEs are reused. Clear stale data and set key fields to + * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. + */ + memset(wqe, 0, sizeof(*wqe)); + + if (opt & INHIBIT_ABORT) + bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); + /* Abort specified xri tag, with the mask deliberately zeroed */ + bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); + + bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); + + /* Abort the I/O associated with this outstanding exchange ID. */ + wqe->abort_cmd.wqe_com.abort_tag = xritag; + + /* iotag for the wqe completion. */ + bf_set(wqe_reqtag, &wqe->abort_cmd.wqe_com, pwqeq->iotag); + + bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1); + bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); + + bf_set(wqe_cmd_type, &wqe->abort_cmd.wqe_com, OTHER_COMMAND); + bf_set(wqe_wqec, &wqe->abort_cmd.wqe_com, 1); + bf_set(wqe_cqid, &wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); +} + static int lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *ctxp, @@ -3347,7 +3386,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, } ndlp = lpfc_findnode_did(phba->pport, sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { atomic_inc(&tgtp->xmt_abort_rsp_error); @@ -3423,7 +3462,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, /* Ready - mark outstanding as aborted by driver. */ abts_wqeq->iocb_flag |= LPFC_DRIVER_ABORTED; - lpfc_nvme_prep_abort_wqe(abts_wqeq, ctxp->wqeq->sli4_xritag, opt); + lpfc_nvmet_prep_abort_wqe(abts_wqeq, ctxp->wqeq->sli4_xritag, opt); /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abts_wqeq->hba_wqidx = ctxp->wqeq->hba_wqidx; @@ -3596,8 +3635,8 @@ out: /** * lpfc_nvmet_invalidate_host * - * @phba - pointer to the driver instance bound to an adapter port. - * @ndlp - pointer to an lpfc_nodelist type + * @phba: pointer to the driver instance bound to an adapter port. + * @ndlp: pointer to an lpfc_nodelist type * * This routine upcalls the nvmet transport to invalidate an NVME * host to which this target instance had active connections. diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 983eeb0e3d07..3b989f720937 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -313,7 +313,7 @@ lpfc_scsi_dev_block(struct lpfc_hba *phba) /** * lpfc_new_scsi_buf_s3 - Scsi buffer allocator for HBA with SLI3 IF spec * @vport: The virtual port for which this call being executed. - * @num_to_allocate: The requested number of buffers to allocate. + * @num_to_alloc: The requested number of buffers to allocate. * * This routine allocates a scsi buffer for device with SLI-3 interface spec, * the scsi buffer contains all the necessary information needed to initiate @@ -497,6 +497,7 @@ lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport) * lpfc_sli4_io_xri_aborted - Fast-path process of fcp xri abort * @phba: pointer to lpfc hba data structure. * @axri: pointer to the fcp xri abort wcqe structure. + * @idx: index into hdwq * * This routine is invoked by the worker thread to process a SLI4 fast-path * FCP or NVME aborted xri. @@ -579,6 +580,8 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, /** * lpfc_get_scsi_buf_s3 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA * @phba: The HBA for which this call is being executed. + * @ndlp: pointer to a node-list data structure. + * @cmnd: Pointer to scsi_cmnd data structure. * * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list * and returns to caller. @@ -618,6 +621,8 @@ lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, /** * lpfc_get_scsi_buf_s4 - Get a scsi buffer from io_buf_list of the HBA * @phba: The HBA for which this call is being executed. + * @ndlp: pointer to a node-list data structure. + * @cmnd: Pointer to scsi_cmnd data structure. * * This routine removes a scsi buffer from head of @hdwq io_buf_list * and returns to caller. @@ -633,7 +638,6 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct lpfc_io_buf *lpfc_cmd; struct lpfc_sli4_hdw_queue *qp; struct sli4_sge *sgl; - IOCB_t *iocb; dma_addr_t pdma_phys_fcp_rsp; dma_addr_t pdma_phys_fcp_cmd; uint32_t cpu, idx; @@ -703,24 +707,6 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, sgl->word2 = cpu_to_le32(sgl->word2); sgl->sge_len = cpu_to_le32(sizeof(struct fcp_rsp)); - /* - * Since the IOCB for the FCP I/O is built into this - * lpfc_io_buf, initialize it with all known data now. - */ - iocb = &lpfc_cmd->cur_iocbq.iocb; - iocb->un.fcpi64.bdl.ulpIoTag32 = 0; - iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_64; - /* setting the BLP size to 2 * sizeof BDE may not be correct. - * We are setting the bpl to point to out sgl. An sgl's - * entries are 16 bytes, a bpl entries are 12 bytes. - */ - iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); - iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_fcp_cmd); - iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_fcp_cmd); - iocb->ulpBdeCount = 1; - iocb->ulpLe = 1; - iocb->ulpClass = CLASS3; - if (lpfc_ndlp_check_qdepth(phba, ndlp)) { atomic_inc(&ndlp->cmd_pending); lpfc_cmd->flags |= LPFC_SBUF_BUMP_QDEPTH; @@ -730,6 +716,8 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, /** * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA * @phba: The HBA for which this call is being executed. + * @ndlp: pointer to a node-list data structure. + * @cmnd: Pointer to scsi_cmnd data structure. * * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list * and returns to caller. @@ -818,6 +806,25 @@ lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_io_buf *psb) } /** + * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB + * @data: A pointer to the immediate command data portion of the IOCB. + * @fcp_cmnd: The FCP Command that is provided by the SCSI layer. + * + * The routine copies the entire FCP command from @fcp_cmnd to @data while + * byte swapping the data to big endian format for transmission on the wire. + **/ +static void +lpfc_fcpcmd_to_iocb(u8 *data, struct fcp_cmnd *fcp_cmnd) +{ + int i, j; + + for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); + i += sizeof(uint32_t), j++) { + ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); + } +} + +/** * lpfc_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be mapped. @@ -953,6 +960,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * we need to set word 4 of IOCB here */ iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); + lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); return 0; } @@ -976,7 +984,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * @sc: The SCSI command to examine * @reftag: (out) BlockGuard reference tag for transmitted data * @apptag: (out) BlockGuard application tag for transmitted data - * @new_guard (in) Value to replace CRC with if needed + * @new_guard: (in) Value to replace CRC with if needed * * Returns BG_ERR_* bit mask or 0 if request ignored **/ @@ -1381,8 +1389,8 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, * the specified SCSI command. * @phba: The Hba for which this call is being executed. * @sc: The SCSI command to examine - * @txopt: (out) BlockGuard operation for transmitted data - * @rxopt: (out) BlockGuard operation for received data + * @txop: (out) BlockGuard operation for transmitted data + * @rxop: (out) BlockGuard operation for received data * * Returns: zero on success; non-zero if tx and/or rx op cannot be determined * @@ -1461,8 +1469,8 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, * the specified SCSI command in order to force a guard tag error. * @phba: The Hba for which this call is being executed. * @sc: The SCSI command to examine - * @txopt: (out) BlockGuard operation for transmitted data - * @rxopt: (out) BlockGuard operation for received data + * @txop: (out) BlockGuard operation for transmitted data + * @rxop: (out) BlockGuard operation for received data * * Returns: zero on success; non-zero if tx and/or rx op cannot be determined * @@ -1533,7 +1541,7 @@ lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, * @phba: The Hba for which this call is being executed. * @sc: pointer to scsi command we're working on * @bpl: pointer to buffer list for protection groups - * @datacnt: number of segments of data that have been dma mapped + * @datasegcnt: number of segments of data that have been dma mapped * * This function sets up BPL buffer list for protection groups of * type LPFC_PG_TYPE_NO_DIF @@ -1920,7 +1928,8 @@ out: * @phba: The Hba for which this call is being executed. * @sc: pointer to scsi command we're working on * @sgl: pointer to buffer list for protection groups - * @datacnt: number of segments of data that have been dma mapped + * @datasegcnt: number of segments of data that have been dma mapped + * @lpfc_cmd: lpfc scsi command object pointer. * * This function sets up SGL buffer list for protection groups of * type LPFC_PG_TYPE_NO_DIF @@ -2094,6 +2103,7 @@ out: * @sgl: pointer to buffer list for protection groups * @datacnt: number of segments of data that have been dma mapped * @protcnt: number of segment of protection data that have been dma mapped + * @lpfc_cmd: lpfc scsi command object pointer. * * This function sets up SGL buffer list for protection groups of * type LPFC_PG_TYPE_DIF @@ -2881,6 +2891,150 @@ out: } } +/* + * This function checks for BlockGuard errors detected by + * the HBA. In case of errors, the ASC/ASCQ fields in the + * sense buffer will be set accordingly, paired with + * ILLEGAL_REQUEST to signal to the kernel that the HBA + * detected corruption. + * + * Returns: + * 0 - No error found + * 1 - BlockGuard error found + * -1 - Internal error (bad profile, ...etc) + */ +static int +lpfc_sli4_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd, + struct lpfc_wcqe_complete *wcqe) +{ + struct scsi_cmnd *cmd = lpfc_cmd->pCmd; + int ret = 0; + u32 status = bf_get(lpfc_wcqe_c_status, wcqe); + u32 bghm = 0; + u32 bgstat = 0; + u64 failing_sector = 0; + + if (status == CQE_STATUS_DI_ERROR) { + if (bf_get(lpfc_wcqe_c_bg_ge, wcqe)) /* Guard Check failed */ + bgstat |= BGS_GUARD_ERR_MASK; + if (bf_get(lpfc_wcqe_c_bg_ae, wcqe)) /* AppTag Check failed */ + bgstat |= BGS_APPTAG_ERR_MASK; + if (bf_get(lpfc_wcqe_c_bg_re, wcqe)) /* RefTag Check failed */ + bgstat |= BGS_REFTAG_ERR_MASK; + + /* Check to see if there was any good data before the error */ + if (bf_get(lpfc_wcqe_c_bg_tdpv, wcqe)) { + bgstat |= BGS_HI_WATER_MARK_PRESENT_MASK; + bghm = wcqe->total_data_placed; + } + + /* + * Set ALL the error bits to indicate we don't know what + * type of error it is. + */ + if (!bgstat) + bgstat |= (BGS_REFTAG_ERR_MASK | BGS_APPTAG_ERR_MASK | + BGS_GUARD_ERR_MASK); + } + + if (lpfc_bgs_get_guard_err(bgstat)) { + ret = 1; + + scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, + 0x10, 0x1); + cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 | + SAM_STAT_CHECK_CONDITION; + phba->bg_guard_err_cnt++; + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, + "9059 BLKGRD: Guard Tag error in cmd" + " 0x%x lba 0x%llx blk cnt 0x%x " + "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], + (unsigned long long)scsi_get_lba(cmd), + blk_rq_sectors(cmd->request), bgstat, bghm); + } + + if (lpfc_bgs_get_reftag_err(bgstat)) { + ret = 1; + + scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, + 0x10, 0x3); + cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 | + SAM_STAT_CHECK_CONDITION; + + phba->bg_reftag_err_cnt++; + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, + "9060 BLKGRD: Ref Tag error in cmd" + " 0x%x lba 0x%llx blk cnt 0x%x " + "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], + (unsigned long long)scsi_get_lba(cmd), + blk_rq_sectors(cmd->request), bgstat, bghm); + } + + if (lpfc_bgs_get_apptag_err(bgstat)) { + ret = 1; + + scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, + 0x10, 0x2); + cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 | + SAM_STAT_CHECK_CONDITION; + + phba->bg_apptag_err_cnt++; + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, + "9062 BLKGRD: App Tag error in cmd" + " 0x%x lba 0x%llx blk cnt 0x%x " + "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], + (unsigned long long)scsi_get_lba(cmd), + blk_rq_sectors(cmd->request), bgstat, bghm); + } + + if (lpfc_bgs_get_hi_water_mark_present(bgstat)) { + /* + * setup sense data descriptor 0 per SPC-4 as an information + * field, and put the failing LBA in it. + * This code assumes there was also a guard/app/ref tag error + * indication. + */ + cmd->sense_buffer[7] = 0xc; /* Additional sense length */ + cmd->sense_buffer[8] = 0; /* Information descriptor type */ + cmd->sense_buffer[9] = 0xa; /* Additional descriptor length */ + cmd->sense_buffer[10] = 0x80; /* Validity bit */ + + /* bghm is a "on the wire" FC frame based count */ + switch (scsi_get_prot_op(cmd)) { + case SCSI_PROT_READ_INSERT: + case SCSI_PROT_WRITE_STRIP: + bghm /= cmd->device->sector_size; + break; + case SCSI_PROT_READ_STRIP: + case SCSI_PROT_WRITE_INSERT: + case SCSI_PROT_READ_PASS: + case SCSI_PROT_WRITE_PASS: + bghm /= (cmd->device->sector_size + + sizeof(struct scsi_dif_tuple)); + break; + } + + failing_sector = scsi_get_lba(cmd); + failing_sector += bghm; + + /* Descriptor Information */ + put_unaligned_be64(failing_sector, &cmd->sense_buffer[12]); + } + + if (!ret) { + /* No error was reported - problem in FW? */ + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, + "9068 BLKGRD: Unknown error in cmd" + " 0x%x lba 0x%llx blk cnt 0x%x " + "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], + (unsigned long long)scsi_get_lba(cmd), + blk_rq_sectors(cmd->request), bgstat, bghm); + + /* Calcuate what type of error it was */ + lpfc_calc_bg_err(phba, lpfc_cmd); + } + return ret; +} /* * This function checks for BlockGuard errors detected by @@ -3050,7 +3204,9 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; struct sli4_sge *first_data_sgl; - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + struct lpfc_iocbq *pwqeq = &lpfc_cmd->cur_iocbq; + struct lpfc_vport *vport = phba->pport; + union lpfc_wqe128 *wqe = &pwqeq->wqe; dma_addr_t physaddr; uint32_t num_bde = 0; uint32_t dma_len; @@ -3191,13 +3347,16 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) if ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || phba->cfg_enable_pbde) { bde = (struct ulp_bde64 *) - &(iocb_cmd->unsli3.sli3Words[5]); + &wqe->words[13]; bde->addrLow = first_data_sgl->addr_lo; bde->addrHigh = first_data_sgl->addr_hi; bde->tus.f.bdeSize = le32_to_cpu(first_data_sgl->sge_len); bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; bde->tus.w = cpu_to_le32(bde->tus.w); + + } else { + memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); } } else { sgl += 1; @@ -3209,11 +3368,15 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) if ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || phba->cfg_enable_pbde) { bde = (struct ulp_bde64 *) - &(iocb_cmd->unsli3.sli3Words[5]); + &wqe->words[13]; memset(bde, 0, (sizeof(uint32_t) * 3)); } } + /* Word 11 */ + if (phba->cfg_enable_pbde) + bf_set(wqe_pbde, &wqe->generic.wqe_com, 1); + /* * Finish initializing those IOCB fields that are dependent on the * scsi_cmnd request_buffer. Note that for SLI-2 the bdeSize is @@ -3221,12 +3384,23 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * all iocb memory resources are reused. */ fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd)); - - /* - * Due to difference in data length between DIF/non-DIF paths, - * we need to set word 4 of IOCB here - */ - iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); + /* Set first-burst provided it was successfully negotiated */ + if (!(phba->hba_flag & HBA_FCOE_MODE) && + vport->cfg_first_burst_size && + scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) { + u32 init_len, total_len; + + total_len = be32_to_cpu(fcp_cmnd->fcpDl); + init_len = min(total_len, vport->cfg_first_burst_size); + + /* Word 4 & 5 */ + wqe->fcp_iwrite.initial_xfer_len = init_len; + wqe->fcp_iwrite.total_xfer_len = total_len; + } else { + /* Word 4 */ + wqe->fcp_iwrite.total_xfer_len = + be32_to_cpu(fcp_cmnd->fcpDl); + } /* * If the OAS driver feature is enabled and the lun is enabled for @@ -3237,6 +3411,17 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) lpfc_cmd->cur_iocbq.iocb_flag |= (LPFC_IO_OAS | LPFC_IO_FOF); lpfc_cmd->cur_iocbq.priority = ((struct lpfc_device_data *) scsi_cmnd->device->hostdata)->priority; + + /* Word 10 */ + bf_set(wqe_oas, &wqe->generic.wqe_com, 1); + bf_set(wqe_ccpe, &wqe->generic.wqe_com, 1); + + if (lpfc_cmd->cur_iocbq.priority) + bf_set(wqe_ccp, &wqe->generic.wqe_com, + (lpfc_cmd->cur_iocbq.priority << 1)); + else + bf_set(wqe_ccp, &wqe->generic.wqe_com, + (phba->cfg_XLanePriority << 1)); } return 0; @@ -3262,7 +3447,8 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; struct sli4_sge *sgl = (struct sli4_sge *)(lpfc_cmd->dma_sgl); - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + struct lpfc_iocbq *pwqeq = &lpfc_cmd->cur_iocbq; + union lpfc_wqe128 *wqe = &pwqeq->wqe; uint32_t num_sge = 0; int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction; int prot_group_type = 0; @@ -3394,28 +3580,50 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, fcpdl = lpfc_bg_scsi_adjust_dl(phba, lpfc_cmd); fcp_cmnd->fcpDl = be32_to_cpu(fcpdl); - /* - * Due to difference in data length between DIF/non-DIF paths, - * we need to set word 4 of IOCB here - */ - iocb_cmd->un.fcpi.fcpi_parm = fcpdl; + /* Set first-burst provided it was successfully negotiated */ + if (!(phba->hba_flag & HBA_FCOE_MODE) && + vport->cfg_first_burst_size && + scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) { + u32 init_len, total_len; - /* - * For First burst, we may need to adjust the initial transfer - * length for DIF - */ - if (iocb_cmd->un.fcpi.fcpi_XRdy && - (fcpdl < vport->cfg_first_burst_size)) - iocb_cmd->un.fcpi.fcpi_XRdy = fcpdl; + total_len = be32_to_cpu(fcp_cmnd->fcpDl); + init_len = min(total_len, vport->cfg_first_burst_size); + + /* Word 4 & 5 */ + wqe->fcp_iwrite.initial_xfer_len = init_len; + wqe->fcp_iwrite.total_xfer_len = total_len; + } else { + /* Word 4 */ + wqe->fcp_iwrite.total_xfer_len = + be32_to_cpu(fcp_cmnd->fcpDl); + } /* * If the OAS driver feature is enabled and the lun is enabled for * OAS, set the oas iocb related flags. */ if ((phba->cfg_fof) && ((struct lpfc_device_data *) - scsi_cmnd->device->hostdata)->oas_enabled) + scsi_cmnd->device->hostdata)->oas_enabled) { lpfc_cmd->cur_iocbq.iocb_flag |= (LPFC_IO_OAS | LPFC_IO_FOF); + /* Word 10 */ + bf_set(wqe_oas, &wqe->generic.wqe_com, 1); + bf_set(wqe_ccpe, &wqe->generic.wqe_com, 1); + bf_set(wqe_ccp, &wqe->generic.wqe_com, + (phba->cfg_XLanePriority << 1)); + } + + /* Word 7. DIF Flags */ + if (lpfc_cmd->cur_iocbq.iocb_flag & LPFC_IO_DIF_PASS) + bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_PASSTHRU); + else if (lpfc_cmd->cur_iocbq.iocb_flag & LPFC_IO_DIF_STRIP) + bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_STRIP); + else if (lpfc_cmd->cur_iocbq.iocb_flag & LPFC_IO_DIF_INSERT) + bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_INSERT); + + lpfc_cmd->cur_iocbq.iocb_flag &= ~(LPFC_IO_DIF_PASS | + LPFC_IO_DIF_STRIP | LPFC_IO_DIF_INSERT); + return 0; err: if (lpfc_cmd->seg_cnt) @@ -3475,6 +3683,26 @@ lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) } /** + * lpfc_scsi_prep_cmnd_buf - Wrapper function for IOCB/WQE mapping of scsi + * buffer + * @phba: The Hba for which this call is being executed. + * @lpfc_cmd: The scsi buffer which is going to be mapped. + * @tmo: Timeout value for IO + * + * This routine initializes IOCB/WQE data structure from scsi command + * + * Return codes: + * 1 - Error + * 0 - Success + **/ +static inline int +lpfc_scsi_prep_cmnd_buf(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, + uint8_t tmo) +{ + return vport->phba->lpfc_scsi_prep_cmnd_buf(vport, lpfc_cmd, tmo); +} + +/** * lpfc_send_scsi_error_event - Posts an event when there is SCSI error * @phba: Pointer to hba context object. * @vport: Pointer to vport object. @@ -3486,17 +3714,16 @@ lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) **/ static void lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport, - struct lpfc_io_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb) { + struct lpfc_io_buf *lpfc_cmd, uint32_t fcpi_parm) { struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; uint32_t resp_info = fcprsp->rspStatus2; uint32_t scsi_status = fcprsp->rspStatus3; - uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; struct lpfc_fast_path_event *fast_path_evt = NULL; struct lpfc_nodelist *pnode = lpfc_cmd->rdata->pnode; unsigned long flags; - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) + if (!pnode) return; /* If there is queuefull or busy condition send a scsi event */ @@ -3606,13 +3833,11 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_io_buf *psb) **/ static void lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, - struct lpfc_iocbq *rsp_iocb) + uint32_t fcpi_parm) { - struct lpfc_hba *phba = vport->phba; struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd; struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; - uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; uint32_t resp_info = fcprsp->rspStatus2; uint32_t scsi_status = fcprsp->rspStatus3; uint32_t *lp; @@ -3747,13 +3972,10 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, */ } else if (fcpi_parm) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, - "9029 FCP %s Check Error xri x%x Data: " + "9029 FCP %s Check Error Data: " "x%x x%x x%x x%x x%x\n", ((cmnd->sc_data_direction == DMA_FROM_DEVICE) ? "Read" : "Write"), - ((phba->sli_rev == LPFC_SLI_REV4) ? - lpfc_cmd->cur_iocbq.sli4_xritag : - rsp_iocb->iocb.ulpContext), fcpDl, be32_to_cpu(fcprsp->rspResId), fcpi_parm, cmnd->cmnd[0], scsi_status); @@ -3780,7 +4002,336 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, out: cmnd->result = host_status << 16 | scsi_status; - lpfc_send_scsi_error_event(vport->phba, vport, lpfc_cmd, rsp_iocb); + lpfc_send_scsi_error_event(vport->phba, vport, lpfc_cmd, fcpi_parm); +} + +/** + * lpfc_fcp_io_cmd_wqe_cmpl - Complete a FCP IO + * @phba: The hba for which this call is being executed. + * @pwqeIn: The command WQE for the scsi cmnd. + * @pwqeOut: The response WQE for the scsi cmnd. + * + * This routine assigns scsi command result by looking into response WQE + * status field appropriately. This routine handles QUEUE FULL condition as + * well by ramping down device queue depth. + **/ +static void +lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, + struct lpfc_wcqe_complete *wcqe) +{ + struct lpfc_io_buf *lpfc_cmd = + (struct lpfc_io_buf *)pwqeIn->context1; + struct lpfc_vport *vport = pwqeIn->vport; + struct lpfc_rport_data *rdata; + struct lpfc_nodelist *ndlp; + struct scsi_cmnd *cmd; + unsigned long flags; + struct lpfc_fast_path_event *fast_path_evt; + struct Scsi_Host *shost; + u32 logit = LOG_FCP; + u32 status, idx; + unsigned long iflags = 0; + + /* Sanity check on return of outstanding command */ + if (!lpfc_cmd) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "9032 Null lpfc_cmd pointer. No " + "release, skip completion\n"); + return; + } + + rdata = lpfc_cmd->rdata; + ndlp = rdata->pnode; + + if (bf_get(lpfc_wcqe_c_xb, wcqe)) { + /* TOREMOVE - currently this flag is checked during + * the release of lpfc_iocbq. Remove once we move + * to lpfc_wqe_job construct. + * + * This needs to be done outside buf_lock + */ + spin_lock_irqsave(&phba->hbalock, iflags); + lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_EXCHANGE_BUSY; + spin_unlock_irqrestore(&phba->hbalock, iflags); + } + + /* Guard against abort handler being called at same time */ + spin_lock(&lpfc_cmd->buf_lock); + + /* Sanity check on return of outstanding command */ + cmd = lpfc_cmd->pCmd; + if (!cmd || !phba) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "9042 I/O completion: Not an active IO\n"); + spin_unlock(&lpfc_cmd->buf_lock); + lpfc_release_scsi_buf(phba, lpfc_cmd); + return; + } + idx = lpfc_cmd->cur_iocbq.hba_wqidx; + if (phba->sli4_hba.hdwq) + phba->sli4_hba.hdwq[idx].scsi_cstat.io_cmpls++; + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO)) + this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io); +#endif + shost = cmd->device->host; + + status = bf_get(lpfc_wcqe_c_status, wcqe); + lpfc_cmd->status = (status & LPFC_IOCB_STATUS_MASK); + lpfc_cmd->result = (wcqe->parameter & IOERR_PARAM_MASK); + + lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY; + if (bf_get(lpfc_wcqe_c_xb, wcqe)) + lpfc_cmd->flags |= LPFC_SBUF_XBUSY; + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (lpfc_cmd->prot_data_type) { + struct scsi_dif_tuple *src = NULL; + + src = (struct scsi_dif_tuple *)lpfc_cmd->prot_data_segment; + /* + * Used to restore any changes to protection + * data for error injection. + */ + switch (lpfc_cmd->prot_data_type) { + case LPFC_INJERR_REFTAG: + src->ref_tag = + lpfc_cmd->prot_data; + break; + case LPFC_INJERR_APPTAG: + src->app_tag = + (uint16_t)lpfc_cmd->prot_data; + break; + case LPFC_INJERR_GUARD: + src->guard_tag = + (uint16_t)lpfc_cmd->prot_data; + break; + default: + break; + } + + lpfc_cmd->prot_data = 0; + lpfc_cmd->prot_data_type = 0; + lpfc_cmd->prot_data_segment = NULL; + } +#endif + if (unlikely(lpfc_cmd->status)) { + if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && + (lpfc_cmd->result & IOERR_DRVR_MASK)) + lpfc_cmd->status = IOSTAT_DRIVER_REJECT; + else if (lpfc_cmd->status >= IOSTAT_CNT) + lpfc_cmd->status = IOSTAT_DEFAULT; + if (lpfc_cmd->status == IOSTAT_FCP_RSP_ERROR && + !lpfc_cmd->fcp_rsp->rspStatus3 && + (lpfc_cmd->fcp_rsp->rspStatus2 & RESID_UNDER) && + !(vport->cfg_log_verbose & LOG_FCP_UNDER)) + logit = 0; + else + logit = LOG_FCP | LOG_FCP_UNDER; + lpfc_printf_vlog(vport, KERN_WARNING, logit, + "9034 FCP cmd x%x failed <%d/%lld> " + "status: x%x result: x%x " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x x%x\n", + cmd->cmnd[0], + cmd->device ? cmd->device->id : 0xffff, + cmd->device ? cmd->device->lun : 0xffff, + lpfc_cmd->status, lpfc_cmd->result, + vport->fc_myDID, + (ndlp) ? ndlp->nlp_DID : 0, + lpfc_cmd->cur_iocbq.sli4_xritag, + wcqe->parameter, wcqe->total_data_placed, + lpfc_cmd->cur_iocbq.iotag); + } + + switch (lpfc_cmd->status) { + case IOSTAT_SUCCESS: + cmd->result = DID_OK << 16; + break; + case IOSTAT_FCP_RSP_ERROR: + lpfc_handle_fcp_err(vport, lpfc_cmd, + pwqeIn->wqe.fcp_iread.total_xfer_len - + wcqe->total_data_placed); + break; + case IOSTAT_NPORT_BSY: + case IOSTAT_FABRIC_BSY: + cmd->result = DID_TRANSPORT_DISRUPTED << 16; + fast_path_evt = lpfc_alloc_fast_evt(phba); + if (!fast_path_evt) + break; + fast_path_evt->un.fabric_evt.event_type = + FC_REG_FABRIC_EVENT; + fast_path_evt->un.fabric_evt.subcategory = + (lpfc_cmd->status == IOSTAT_NPORT_BSY) ? + LPFC_EVENT_PORT_BUSY : LPFC_EVENT_FABRIC_BUSY; + if (ndlp) { + memcpy(&fast_path_evt->un.fabric_evt.wwpn, + &ndlp->nlp_portname, + sizeof(struct lpfc_name)); + memcpy(&fast_path_evt->un.fabric_evt.wwnn, + &ndlp->nlp_nodename, + sizeof(struct lpfc_name)); + } + fast_path_evt->vport = vport; + fast_path_evt->work_evt.evt = + LPFC_EVT_FASTPATH_MGMT_EVT; + spin_lock_irqsave(&phba->hbalock, flags); + list_add_tail(&fast_path_evt->work_evt.evt_listp, + &phba->work_list); + spin_unlock_irqrestore(&phba->hbalock, flags); + lpfc_worker_wake_up(phba); + lpfc_printf_vlog(vport, KERN_WARNING, logit, + "9035 Fabric/Node busy FCP cmd x%x failed" + " <%d/%lld> " + "status: x%x result: x%x " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x x%x\n", + cmd->cmnd[0], + cmd->device ? cmd->device->id : 0xffff, + cmd->device ? cmd->device->lun : 0xffff, + lpfc_cmd->status, lpfc_cmd->result, + vport->fc_myDID, + (ndlp) ? ndlp->nlp_DID : 0, + lpfc_cmd->cur_iocbq.sli4_xritag, + wcqe->parameter, + wcqe->total_data_placed, + lpfc_cmd->cur_iocbq.iocb.ulpIoTag); + break; + case IOSTAT_REMOTE_STOP: + if (ndlp) { + /* This I/O was aborted by the target, we don't + * know the rxid and because we did not send the + * ABTS we cannot generate and RRQ. + */ + lpfc_set_rrq_active(phba, ndlp, + lpfc_cmd->cur_iocbq.sli4_lxritag, + 0, 0); + } + fallthrough; + case IOSTAT_LOCAL_REJECT: + if (lpfc_cmd->result & IOERR_DRVR_MASK) + lpfc_cmd->status = IOSTAT_DRIVER_REJECT; + if (lpfc_cmd->result == IOERR_ELXSEC_KEY_UNWRAP_ERROR || + lpfc_cmd->result == + IOERR_ELXSEC_KEY_UNWRAP_COMPARE_ERROR || + lpfc_cmd->result == IOERR_ELXSEC_CRYPTO_ERROR || + lpfc_cmd->result == + IOERR_ELXSEC_CRYPTO_COMPARE_ERROR) { + cmd->result = DID_NO_CONNECT << 16; + break; + } + if (lpfc_cmd->result == IOERR_INVALID_RPI || + lpfc_cmd->result == IOERR_NO_RESOURCES || + lpfc_cmd->result == IOERR_ABORT_REQUESTED || + lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) { + cmd->result = DID_REQUEUE << 16; + break; + } + if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED || + lpfc_cmd->result == IOERR_TX_DMA_FAILED) && + status == CQE_STATUS_DI_ERROR) { + if (scsi_get_prot_op(cmd) != + SCSI_PROT_NORMAL) { + /* + * This is a response for a BG enabled + * cmd. Parse BG error + */ + lpfc_sli4_parse_bg_err(phba, lpfc_cmd, + wcqe); + break; + } + lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, + "9040 non-zero BGSTAT on unprotected cmd\n"); + } + lpfc_printf_vlog(vport, KERN_WARNING, logit, + "9036 Local Reject FCP cmd x%x failed" + " <%d/%lld> " + "status: x%x result: x%x " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x x%x\n", + cmd->cmnd[0], + cmd->device ? cmd->device->id : 0xffff, + cmd->device ? cmd->device->lun : 0xffff, + lpfc_cmd->status, lpfc_cmd->result, + vport->fc_myDID, + (ndlp) ? ndlp->nlp_DID : 0, + lpfc_cmd->cur_iocbq.sli4_xritag, + wcqe->parameter, + wcqe->total_data_placed, + lpfc_cmd->cur_iocbq.iocb.ulpIoTag); + fallthrough; + default: + if (lpfc_cmd->status >= IOSTAT_CNT) + lpfc_cmd->status = IOSTAT_DEFAULT; + cmd->result = DID_ERROR << 16; + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, + "9037 FCP Completion Error: xri %x " + "status x%x result x%x [x%x] " + "placed x%x\n", + lpfc_cmd->cur_iocbq.sli4_xritag, + lpfc_cmd->status, lpfc_cmd->result, + wcqe->parameter, + wcqe->total_data_placed); + } + if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) { + u32 *lp = (u32 *)cmd->sense_buffer; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, + "9039 Iodone <%d/%llu> cmd x%p, error " + "x%x SNS x%x x%x Data: x%x x%x\n", + cmd->device->id, cmd->device->lun, cmd, + cmd->result, *lp, *(lp + 3), cmd->retries, + scsi_get_resid(cmd)); + } + + lpfc_update_stats(vport, lpfc_cmd); + + if (vport->cfg_max_scsicmpl_time && + time_after(jiffies, lpfc_cmd->start_time + + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { + spin_lock_irqsave(shost->host_lock, flags); + if (ndlp) { + if (ndlp->cmd_qdepth > + atomic_read(&ndlp->cmd_pending) && + (atomic_read(&ndlp->cmd_pending) > + LPFC_MIN_TGT_QDEPTH) && + (cmd->cmnd[0] == READ_10 || + cmd->cmnd[0] == WRITE_10)) + ndlp->cmd_qdepth = + atomic_read(&ndlp->cmd_pending); + + ndlp->last_change_time = jiffies; + } + spin_unlock_irqrestore(shost->host_lock, flags); + } + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (lpfc_cmd->ts_cmd_start) { + lpfc_cmd->ts_isr_cmpl = lpfc_cmd->cur_iocbq.isr_timestamp; + lpfc_cmd->ts_data_io = ktime_get_ns(); + phba->ktime_last_cmd = lpfc_cmd->ts_data_io; + lpfc_io_ktime(phba, lpfc_cmd); + } +#endif + lpfc_cmd->pCmd = NULL; + spin_unlock(&lpfc_cmd->buf_lock); + + /* The sdev is not guaranteed to be valid post scsi_done upcall. */ + cmd->scsi_done(cmd); + + /* + * If there is an abort thread waiting for command completion + * wake up the thread. + */ + spin_lock(&lpfc_cmd->buf_lock); + lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_DRIVER_ABORTED; + if (lpfc_cmd->waitq) + wake_up(lpfc_cmd->waitq); + spin_unlock(&lpfc_cmd->buf_lock); + + lpfc_release_scsi_buf(phba, lpfc_cmd); } /** @@ -3903,7 +4454,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, switch (lpfc_cmd->status) { case IOSTAT_FCP_RSP_ERROR: /* Call FCP RSP handler to determine result */ - lpfc_handle_fcp_err(vport, lpfc_cmd, pIocbOut); + lpfc_handle_fcp_err(vport, lpfc_cmd, + pIocbOut->iocb.un.fcpi.fcpi_parm); break; case IOSTAT_NPORT_BSY: case IOSTAT_FABRIC_BSY: @@ -3916,7 +4468,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, fast_path_evt->un.fabric_evt.subcategory = (lpfc_cmd->status == IOSTAT_NPORT_BSY) ? LPFC_EVENT_PORT_BUSY : LPFC_EVENT_FABRIC_BUSY; - if (pnode && NLP_CHK_NODE_ACT(pnode)) { + if (pnode) { memcpy(&fast_path_evt->un.fabric_evt.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); @@ -3971,7 +4523,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } if ((lpfc_cmd->status == IOSTAT_REMOTE_STOP) && (phba->sli_rev == LPFC_SLI_REV4) - && (pnode && NLP_CHK_NODE_ACT(pnode))) { + && pnode) { /* This IO was aborted by the target, we don't * know the rxid and because we did not send the * ABTS we cannot generate and RRQ. @@ -3986,8 +4538,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, break; } - if (!pnode || !NLP_CHK_NODE_ACT(pnode) - || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) + if (!pnode || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) cmd->result = DID_TRANSPORT_DISRUPTED << 16 | SAM_STAT_BUSY; } else @@ -4009,7 +4560,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, time_after(jiffies, lpfc_cmd->start_time + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { spin_lock_irqsave(shost->host_lock, flags); - if (pnode && NLP_CHK_NODE_ACT(pnode)) { + if (pnode) { if (pnode->cmd_qdepth > atomic_read(&pnode->cmd_pending) && (atomic_read(&pnode->cmd_pending) > @@ -4053,72 +4604,30 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } /** - * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB - * @data: A pointer to the immediate command data portion of the IOCB. - * @fcp_cmnd: The FCP Command that is provided by the SCSI layer. + * lpfc_scsi_prep_cmnd_buf_s3 - SLI-3 IOCB init for the IO + * @phba: Pointer to vport object for which I/O is executed + * @lpfc_cmd: The scsi buffer which is going to be prep'ed. + * @tmo: timeout value for the IO * - * The routine copies the entire FCP command from @fcp_cmnd to @data while - * byte swapping the data to big endian format for transmission on the wire. - **/ -static void -lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) -{ - int i, j; - for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); - i += sizeof(uint32_t), j++) { - ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); - } -} - -/** - * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit - * @vport: The virtual port for which this call is being executed. - * @lpfc_cmd: The scsi command which needs to send. - * @pnode: Pointer to lpfc_nodelist. + * Based on the data-direction of the command, initialize IOCB + * in the I/O buffer. Fill in the IOCB fields which are independent + * of the scsi buffer * - * This routine initializes fcp_cmnd and iocb data structure from scsi command - * to transfer for device with SLI3 interface spec. + * RETURNS 0 - SUCCESS, **/ -static void -lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, - struct lpfc_nodelist *pnode) +static int lpfc_scsi_prep_cmnd_buf_s3(struct lpfc_vport *vport, + struct lpfc_io_buf *lpfc_cmd, + uint8_t tmo) { - struct lpfc_hba *phba = vport->phba; + IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + struct lpfc_iocbq *piocbq = &lpfc_cmd->cur_iocbq; struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; - struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); - struct lpfc_sli4_hdw_queue *hdwq = NULL; + struct lpfc_nodelist *pnode = lpfc_cmd->ndlp; int datadir = scsi_cmnd->sc_data_direction; - int idx; - uint8_t *ptr; - bool sli4; - uint32_t fcpdl; - - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) - return; - - lpfc_cmd->fcp_rsp->rspSnsLen = 0; - /* clear task management bits */ - lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; - - int_to_scsilun(lpfc_cmd->pCmd->device->lun, - &lpfc_cmd->fcp_cmnd->fcp_lun); + u32 fcpdl; - ptr = &fcp_cmnd->fcpCdb[0]; - memcpy(ptr, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); - if (scsi_cmnd->cmd_len < LPFC_FCP_CDB_LEN) { - ptr += scsi_cmnd->cmd_len; - memset(ptr, 0, (LPFC_FCP_CDB_LEN - scsi_cmnd->cmd_len)); - } - - fcp_cmnd->fcpCntl1 = SIMPLE_Q; - - sli4 = (phba->sli_rev == LPFC_SLI_REV4); piocbq->iocb.un.fcpi.fcpi_XRdy = 0; - idx = lpfc_cmd->hdwq_no; - if (phba->sli4_hba.hdwq) - hdwq = &phba->sli4_hba.hdwq[idx]; /* * There are three possibilities here - use scatter-gather segment, use @@ -4132,42 +4641,31 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, iocb_cmd->ulpPU = PARM_READ_CHECK; if (vport->cfg_first_burst_size && (pnode->nlp_flag & NLP_FIRSTBURST)) { + u32 xrdy_len; + fcpdl = scsi_bufflen(scsi_cmnd); - if (fcpdl < vport->cfg_first_burst_size) - piocbq->iocb.un.fcpi.fcpi_XRdy = fcpdl; - else - piocbq->iocb.un.fcpi.fcpi_XRdy = - vport->cfg_first_burst_size; + xrdy_len = min(fcpdl, + vport->cfg_first_burst_size); + piocbq->iocb.un.fcpi.fcpi_XRdy = xrdy_len; } fcp_cmnd->fcpCntl3 = WRITE_DATA; - if (hdwq) - hdwq->scsi_cstat.output_requests++; } else { iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR; iocb_cmd->ulpPU = PARM_READ_CHECK; fcp_cmnd->fcpCntl3 = READ_DATA; - if (hdwq) - hdwq->scsi_cstat.input_requests++; } } else { iocb_cmd->ulpCommand = CMD_FCP_ICMND64_CR; iocb_cmd->un.fcpi.fcpi_parm = 0; iocb_cmd->ulpPU = 0; fcp_cmnd->fcpCntl3 = 0; - if (hdwq) - hdwq->scsi_cstat.control_requests++; } - if (phba->sli_rev == 3 && - !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) - lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); + /* * Finish initializing those IOCB fields that are independent * of the scsi_cmnd request_buffer */ piocbq->iocb.ulpContext = pnode->nlp_rpi; - if (sli4) - piocbq->iocb.ulpContext = - phba->sli4_hba.rpi_ids[pnode->nlp_rpi]; if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE) piocbq->iocb.ulpFCP2Rcvy = 1; else @@ -4175,9 +4673,159 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f); piocbq->context1 = lpfc_cmd; - piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; - piocbq->iocb.ulpTimeout = lpfc_cmd->timeout; + if (!piocbq->iocb_cmpl) + piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; + piocbq->iocb.ulpTimeout = tmo; piocbq->vport = vport; + return 0; +} + +/** + * lpfc_scsi_prep_cmnd_buf_s4 - SLI-4 WQE init for the IO + * @phba: Pointer to vport object for which I/O is executed + * @lpfc_cmd: The scsi buffer which is going to be prep'ed. + * @tmo: timeout value for the IO + * + * Based on the data-direction of the command copy WQE template + * to I/O buffer WQE. Fill in the WQE fields which are independent + * of the scsi buffer + * + * RETURNS 0 - SUCCESS, + **/ +static int lpfc_scsi_prep_cmnd_buf_s4(struct lpfc_vport *vport, + struct lpfc_io_buf *lpfc_cmd, + uint8_t tmo) +{ + struct lpfc_hba *phba = vport->phba; + struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; + struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; + struct lpfc_sli4_hdw_queue *hdwq = NULL; + struct lpfc_iocbq *pwqeq = &lpfc_cmd->cur_iocbq; + struct lpfc_nodelist *pnode = lpfc_cmd->ndlp; + union lpfc_wqe128 *wqe = &pwqeq->wqe; + u16 idx = lpfc_cmd->hdwq_no; + int datadir = scsi_cmnd->sc_data_direction; + + hdwq = &phba->sli4_hba.hdwq[idx]; + + /* Initialize 64 bytes only */ + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* + * There are three possibilities here - use scatter-gather segment, use + * the single mapping, or neither. + */ + if (scsi_sg_count(scsi_cmnd)) { + if (datadir == DMA_TO_DEVICE) { + /* From the iwrite template, initialize words 7 - 11 */ + memcpy(&wqe->words[7], + &lpfc_iwrite_cmd_template.words[7], + sizeof(uint32_t) * 5); + + fcp_cmnd->fcpCntl3 = WRITE_DATA; + if (hdwq) + hdwq->scsi_cstat.output_requests++; + } else { + /* From the iread template, initialize words 7 - 11 */ + memcpy(&wqe->words[7], + &lpfc_iread_cmd_template.words[7], + sizeof(uint32_t) * 5); + + /* Word 7 */ + bf_set(wqe_tmo, &wqe->fcp_iread.wqe_com, tmo); + + fcp_cmnd->fcpCntl3 = READ_DATA; + if (hdwq) + hdwq->scsi_cstat.input_requests++; + } + } else { + /* From the icmnd template, initialize words 4 - 11 */ + memcpy(&wqe->words[4], &lpfc_icmnd_cmd_template.words[4], + sizeof(uint32_t) * 8); + + /* Word 7 */ + bf_set(wqe_tmo, &wqe->fcp_icmd.wqe_com, tmo); + + fcp_cmnd->fcpCntl3 = 0; + if (hdwq) + hdwq->scsi_cstat.control_requests++; + } + + /* + * Finish initializing those WQE fields that are independent + * of the request_buffer + */ + + /* Word 3 */ + bf_set(payload_offset_len, &wqe->fcp_icmd, + sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); + + /* Word 6 */ + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + phba->sli4_hba.rpi_ids[pnode->nlp_rpi]); + bf_set(wqe_xri_tag, &wqe->generic.wqe_com, pwqeq->sli4_xritag); + + /* Word 7*/ + if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE) + bf_set(wqe_erp, &wqe->generic.wqe_com, 1); + + bf_set(wqe_class, &wqe->generic.wqe_com, + (pnode->nlp_fcp_info & 0x0f)); + + /* Word 8 */ + wqe->generic.wqe_com.abort_tag = pwqeq->iotag; + + /* Word 9 */ + bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag); + + pwqeq->vport = vport; + pwqeq->vport = vport; + pwqeq->context1 = lpfc_cmd; + pwqeq->hba_wqidx = lpfc_cmd->hdwq_no; + pwqeq->wqe_cmpl = lpfc_fcp_io_cmd_wqe_cmpl; + + return 0; +} + +/** + * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit + * @vport: The virtual port for which this call is being executed. + * @lpfc_cmd: The scsi command which needs to send. + * @pnode: Pointer to lpfc_nodelist. + * + * This routine initializes fcp_cmnd and iocb data structure from scsi command + * to transfer for device with SLI3 interface spec. + **/ +static int +lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, + struct lpfc_nodelist *pnode) +{ + struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; + struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; + u8 *ptr; + + if (!pnode) + return 0; + + lpfc_cmd->fcp_rsp->rspSnsLen = 0; + /* clear task management bits */ + lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; + + int_to_scsilun(lpfc_cmd->pCmd->device->lun, + &lpfc_cmd->fcp_cmnd->fcp_lun); + + ptr = &fcp_cmnd->fcpCdb[0]; + memcpy(ptr, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); + if (scsi_cmnd->cmd_len < LPFC_FCP_CDB_LEN) { + ptr += scsi_cmnd->cmd_len; + memset(ptr, 0, (LPFC_FCP_CDB_LEN - scsi_cmnd->cmd_len)); + } + + fcp_cmnd->fcpCntl1 = SIMPLE_Q; + + lpfc_scsi_prep_cmnd_buf(vport, lpfc_cmd, lpfc_cmd->timeout); + + return 0; } /** @@ -4206,8 +4854,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *ndlp = rdata->pnode; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || - ndlp->nlp_state != NLP_STE_MAPPED_NODE) + if (!ndlp || ndlp->nlp_state != NLP_STE_MAPPED_NODE) return 0; piocbq = &(lpfc_cmd->cur_iocbq); @@ -4264,7 +4911,6 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) { phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf; - phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd; switch (dev_grp) { case LPFC_PCI_DEV_LP: @@ -4272,19 +4918,20 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s3; phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3; phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s3; + phba->lpfc_scsi_prep_cmnd_buf = lpfc_scsi_prep_cmnd_buf_s3; break; case LPFC_PCI_DEV_OC: phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4; phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s4; phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4; phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4; + phba->lpfc_scsi_prep_cmnd_buf = lpfc_scsi_prep_cmnd_buf_s4; break; default: lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1418 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth; phba->lpfc_scsi_cmd_iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; @@ -4466,12 +5113,11 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba) /** * lpfc_poll_timeout - Restart polling timer - * @ptr: Map to lpfc_hba data structure pointer. + * @t: Timer construct where lpfc_hba data structure pointer is obtained. * * This routine restarts fcp_poll timer, when FCP ring polling is enable * and FCP Ring interrupt is disable. **/ - void lpfc_poll_timeout(struct timer_list *t) { struct lpfc_hba *phba = from_timer(phba, t, fcp_poll_timer); @@ -4487,8 +5133,8 @@ void lpfc_poll_timeout(struct timer_list *t) /** * lpfc_queuecommand - scsi_host_template queuecommand entry point + * @shost: kernel scsi host pointer. * @cmnd: Pointer to scsi_cmnd data structure. - * @done: Pointer to done routine. * * Driver registers this routine to scsi midlayer to submit a @cmd to process. * This routine prepares an IOCB from scsi command and provides to firmware. @@ -4544,7 +5190,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) * Catch race where our node has transitioned, but the * transport is still transitioning. */ - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) goto out_tgt_busy; if (lpfc_ndlp_check_qdepth(phba, ndlp)) { if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) { @@ -4594,8 +5240,13 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) lpfc_cmd->pCmd = cmnd; lpfc_cmd->rdata = rdata; lpfc_cmd->ndlp = ndlp; + lpfc_cmd->cur_iocbq.iocb_cmpl = NULL; cmnd->host_scribble = (unsigned char *)lpfc_cmd; + err = lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); + if (err) + goto out_host_busy_release_buf; + if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { if (vport->phba->cfg_enable_bg) { lpfc_printf_vlog(vport, @@ -4631,14 +5282,15 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) goto out_host_busy_free_buf; } - lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO)) this_cpu_inc(phba->sli4_hba.c_stat->xmt_io); #endif - err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, - &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); + /* Issue I/O to adapter */ + err = lpfc_sli_issue_fcp_io(phba, LPFC_FCP_RING, + &lpfc_cmd->cur_iocbq, + SLI_IOCB_RET_IOCB); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (start) { lpfc_cmd->ts_cmd_start = start; @@ -4650,24 +5302,30 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) #endif if (err) { lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "3376 FCP could not issue IOCB err %x" - "FCP cmd x%x <%d/%llu> " - "sid: x%x did: x%x oxid: x%x " - "Data: x%x x%x x%x x%x\n", - err, cmnd->cmnd[0], - cmnd->device ? cmnd->device->id : 0xffff, - cmnd->device ? cmnd->device->lun : (u64) -1, - vport->fc_myDID, ndlp->nlp_DID, - phba->sli_rev == LPFC_SLI_REV4 ? - lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff, - lpfc_cmd->cur_iocbq.iocb.ulpContext, - lpfc_cmd->cur_iocbq.iocb.ulpIoTag, - lpfc_cmd->cur_iocbq.iocb.ulpTimeout, - (uint32_t) - (cmnd->request->timeout / 1000)); + "3376 FCP could not issue IOCB err %x " + "FCP cmd x%x <%d/%llu> " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x x%x x%x\n", + err, cmnd->cmnd[0], + cmnd->device ? cmnd->device->id : 0xffff, + cmnd->device ? cmnd->device->lun : (u64)-1, + vport->fc_myDID, ndlp->nlp_DID, + phba->sli_rev == LPFC_SLI_REV4 ? + lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff, + phba->sli_rev == LPFC_SLI_REV4 ? + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi] : + lpfc_cmd->cur_iocbq.iocb.ulpContext, + lpfc_cmd->cur_iocbq.iotag, + phba->sli_rev == LPFC_SLI_REV4 ? + bf_get(wqe_tmo, + &lpfc_cmd->cur_iocbq.wqe.generic.wqe_com) : + lpfc_cmd->cur_iocbq.iocb.ulpTimeout, + (uint32_t) + (cmnd->request->timeout / 1000)); goto out_host_busy_free_buf; } + if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, &phba->sli.sli3_ring[LPFC_FCP_RING], HA_R0RE_REQ); @@ -4696,6 +5354,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) phba->sli4_hba.hdwq[idx].scsi_cstat.control_requests--; } } + out_host_busy_release_buf: lpfc_release_scsi_buf(phba, lpfc_cmd); out_host_busy: return SCSI_MLQUEUE_HOST_BUSY; @@ -4729,11 +5388,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *iocb; - struct lpfc_iocbq *abtsiocb; struct lpfc_io_buf *lpfc_cmd; - IOCB_t *cmd, *icmd; int ret = SUCCESS, status = 0; struct lpfc_sli_ring *pring_s4 = NULL; + struct lpfc_sli_ring *pring = NULL; int ret_val; unsigned long flags; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); @@ -4810,64 +5468,22 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) goto wait_for_cmpl; } - abtsiocb = __lpfc_sli_get_iocbq(phba); - if (abtsiocb == NULL) { - ret = FAILED; - goto out_unlock_ring; - } - - /* Indicate the IO is being aborted by the driver. */ - iocb->iocb_flag |= LPFC_DRIVER_ABORTED; - - /* - * The scsi command can not be in txq and it is in flight because the - * pCmd is still pointig at the SCSI command we have to abort. There - * is no need to search the txcmplq. Just send an abort to the FW. - */ - - cmd = &iocb->iocb; - icmd = &abtsiocb->iocb; - icmd->un.acxri.abortType = ABORT_TYPE_ABTS; - icmd->un.acxri.abortContextTag = cmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) - icmd->un.acxri.abortIoTag = iocb->sli4_xritag; - else - icmd->un.acxri.abortIoTag = cmd->ulpIoTag; - - icmd->ulpLe = 1; - icmd->ulpClass = cmd->ulpClass; - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocb->hba_wqidx = iocb->hba_wqidx; - abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; - if (iocb->iocb_flag & LPFC_IO_FOF) - abtsiocb->iocb_flag |= LPFC_IO_FOF; - - if (lpfc_is_link_up(phba)) - icmd->ulpCommand = CMD_ABORT_XRI_CN; - else - icmd->ulpCommand = CMD_CLOSE_XRI_CN; - - abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - abtsiocb->vport = vport; lpfc_cmd->waitq = &waitq; if (phba->sli_rev == LPFC_SLI_REV4) { - /* Note: both hbalock and ring_lock must be set here */ - ret_val = __lpfc_sli_issue_iocb(phba, pring_s4->ringno, - abtsiocb, 0); spin_unlock(&pring_s4->ring_lock); + ret_val = lpfc_sli4_issue_abort_iotag(phba, iocb, + lpfc_sli4_abort_fcp_cmpl); } else { - ret_val = __lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, - abtsiocb, 0); + pring = &phba->sli.sli3_ring[LPFC_FCP_RING]; + ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocb, + lpfc_sli_abort_fcp_cmpl); } - if (ret_val == IOCB_ERROR) { + if (ret_val != IOCB_SUCCESS) { /* Indicate the IO is not being aborted by the driver. */ - iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; lpfc_cmd->waitq = NULL; spin_unlock(&lpfc_cmd->buf_lock); spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_sli_release_iocbq(phba, abtsiocb); ret = FAILED; goto out; } @@ -4881,7 +5497,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) &phba->sli.sli3_ring[LPFC_FCP_RING], HA_R0RE_REQ); wait_for_cmpl: - /* Wait for abort to complete */ + /* + * iocb_flag is set to LPFC_DRIVER_ABORTED before we wait + * for abort to complete. + */ wait_event_timeout(waitq, (lpfc_cmd->pCmd != cmnd), msecs_to_jiffies(2*vport->cfg_devloss_tmo*1000)); @@ -5016,7 +5635,7 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) /** * lpfc_send_taskmgmt - Generic SCSI Task Mgmt Handler * @vport: The virtual port for which this call is being executed. - * @rdata: Pointer to remote port local data + * @cmnd: Pointer to scsi_cmnd data structure. * @tgt_id: Target ID of remote device. * @lun_id: Lun number for the TMF * @task_mgmt_cmd: type of TMF to send @@ -5043,7 +5662,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, int status; rdata = lpfc_rport_data_from_scsi_device(cmnd->device); - if (!rdata || !rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) + if (!rdata || !rdata->pnode) return FAILED; pnode = rdata->pnode; @@ -5147,7 +5766,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) */ later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; while (time_after(later, jiffies)) { - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) + if (!pnode) return FAILED; if (pnode->nlp_state == NLP_STE_MAPPED_NODE) return SUCCESS; @@ -5157,8 +5776,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) return FAILED; pnode = rdata->pnode; } - if (!pnode || !NLP_CHK_NODE_ACT(pnode) || - (pnode->nlp_state != NLP_STE_MAPPED_NODE)) + if (!pnode || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) return FAILED; return SUCCESS; } @@ -5320,10 +5938,10 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0722 Target Reset rport failure: rdata x%px\n", rdata); if (pnode) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&pnode->lock); pnode->nlp_flag &= ~NLP_NPR_ADISC; pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&pnode->lock); } lpfc_reset_flush_io_context(vport, tgt_id, lun_id, LPFC_CTX_TGT); @@ -5402,8 +6020,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) match = 0; spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; + if (vport->phba->cfg_fcp2_no_tgt_reset && (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE)) continue; @@ -5665,10 +6282,11 @@ lpfc_slave_destroy(struct scsi_device *sdev) /** * lpfc_create_device_data - creates and initializes device data structure for OAS - * @pha: Pointer to host bus adapter structure. + * @phba: Pointer to host bus adapter structure. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information * @lun: Lun on target + * @pri: Priority * @atomic_create: Flag to indicate if memory should be allocated using the * GFP_ATOMIC flag or not. * @@ -5718,7 +6336,7 @@ lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, /** * lpfc_delete_device_data - frees a device data structure for OAS - * @pha: Pointer to host bus adapter structure. + * @phba: Pointer to host bus adapter structure. * @lun_info: Pointer to device data structure to free. * * This routine frees the previously allocated device data structure passed. @@ -5741,7 +6359,7 @@ lpfc_delete_device_data(struct lpfc_hba *phba, /** * __lpfc_get_device_data - returns the device data for the specified lun - * @pha: Pointer to host bus adapter structure. + * @phba: Pointer to host bus adapter structure. * @list: Point to list to search. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information @@ -5783,7 +6401,7 @@ __lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list, /** * lpfc_find_next_oas_lun - searches for the next oas lun - * @pha: Pointer to host bus adapter structure. + * @phba: Pointer to host bus adapter structure. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information * @starting_lun: Pointer to the lun to start searching for @@ -5791,6 +6409,7 @@ __lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list, * @found_target_wwpn: Pointer to the found lun's target wwpn information * @found_lun: Pointer to the found lun. * @found_lun_status: Pointer to status of the found lun. + * @found_lun_pri: Pointer to priority of the found lun. * * This routine searches the luns list for the specified lun * or the first lun for the vport/target. If the vport wwpn contains @@ -5885,10 +6504,11 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, /** * lpfc_enable_oas_lun - enables a lun for OAS operations - * @pha: Pointer to host bus adapter structure. + * @phba: Pointer to host bus adapter structure. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information * @lun: Lun + * @pri: Priority * * This routine enables a lun for oas operations. The routines does so by * doing the following : @@ -5945,10 +6565,11 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, /** * lpfc_disable_oas_lun - disables a lun for OAS operations - * @pha: Pointer to host bus adapter structure. + * @phba: Pointer to host bus adapter structure. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information * @lun: Lun + * @pri: Priority * * This routine disables a lun for oas operations. The routines does so by * doing the following : @@ -6029,7 +6650,7 @@ struct scsi_host_template lpfc_template_nvme = { .sg_tablesize = 1, .cmd_per_lun = 1, .shost_attrs = lpfc_hba_attrs, - .max_sectors = 0xFFFF, + .max_sectors = 0xFFFFFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .track_queue_depth = 0, }; @@ -6054,7 +6675,7 @@ struct scsi_host_template lpfc_template = { .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, .shost_attrs = lpfc_hba_attrs, - .max_sectors = 0xFFFF, + .max_sectors = 0xFFFFFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .change_queue_depth = scsi_change_queue_depth, .track_queue_depth = 1, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e158cd77d387..95caad764fb7 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -90,12 +90,138 @@ static void __lpfc_sli4_consume_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_cqe *cqe); +union lpfc_wqe128 lpfc_iread_cmd_template; +union lpfc_wqe128 lpfc_iwrite_cmd_template; +union lpfc_wqe128 lpfc_icmnd_cmd_template; + static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) { return &iocbq->iocb; } +/* Setup WQE templates for IOs */ +void lpfc_wqe_cmd_template(void) +{ + union lpfc_wqe128 *wqe; + + /* IREAD template */ + wqe = &lpfc_iread_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - cmd_buff_len, payload_offset_len is zero */ + + /* Word 4 - total_xfer_len is variable */ + + /* Word 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_iread.wqe_com, CMD_FCP_IREAD64_WQE); + bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, PARM_READ_CHECK); + bf_set(wqe_class, &wqe->fcp_iread.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_iread.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0); + bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); + bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4); + bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1); + + /* Word 11 - pbde is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, COMMAND_DATA_IN); + bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 0); + + /* Word 12 - is zero */ + + /* Word 13, 14, 15 - PBDE is variable */ + + /* IWRITE template */ + wqe = &lpfc_iwrite_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - cmd_buff_len, payload_offset_len is zero */ + + /* Word 4 - total_xfer_len is variable */ + + /* Word 5 - initial_xfer_len is variable */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_iwrite.wqe_com, CMD_FCP_IWRITE64_WQE); + bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, PARM_READ_CHECK); + bf_set(wqe_class, &wqe->fcp_iwrite.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_iwrite.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0); + bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); + bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4); + bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); + + /* Word 11 - pbde is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, COMMAND_DATA_OUT); + bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0); + + /* Word 12 - is zero */ + + /* Word 13, 14, 15 - PBDE is variable */ + + /* ICMND template */ + wqe = &lpfc_icmnd_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - payload_offset_len is variable */ + + /* Word 4, 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_icmd.wqe_com, CMD_FCP_ICMND64_WQE); + bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_icmd.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1); + bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_NONE); + bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE); + bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1); + + /* Word 11 */ + bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, COMMAND_DATA_IN); + bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0); + + /* Word 12, 13, 14, 15 - is zero */ +} + #if defined(CONFIG_64BIT) && defined(__LITTLE_ENDIAN) /** * lpfc_sli4_pcimem_bcopy - SLI4 memory copy function @@ -150,6 +276,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) /* sanity check on queue memory */ if (unlikely(!q)) return -ENOMEM; + temp_wqe = lpfc_sli4_qe(q, q->host_index); /* If the host has not yet processed the next entry then we are done */ @@ -860,7 +987,7 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba, { struct lpfc_nodelist *ndlp = NULL; - if ((rrq->vport) && NLP_CHK_NODE_ACT(rrq->ndlp)) + if (rrq->vport) ndlp = lpfc_findnode_did(rrq->vport, rrq->nlp_DID); /* The target DID could have been swapped (cable swap) @@ -1061,12 +1188,6 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, goto out; } - /* - * set the active bit even if there is no mem available. - */ - if (NLP_CHK_FREE_REQ(ndlp)) - goto out; - if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING)) goto out; @@ -1289,6 +1410,11 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) (sglq->state != SGL_XRI_ABORTED)) { spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock, iflag); + + /* Check if we can get a reference on ndlp */ + if (sglq->ndlp && !lpfc_nlp_get(sglq->ndlp)) + sglq->ndlp = NULL; + list_add(&sglq->list, &phba->sli4_hba.lpfc_abts_els_sgl_list); spin_unlock_irqrestore( @@ -2449,10 +2575,10 @@ __lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->nlp_flag & NLP_RELEASE_RPI) { lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); - spin_lock_irqsave(&vport->phba->ndlp_lock, iflags); + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag &= ~NLP_RELEASE_RPI; ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - spin_unlock_irqrestore(&vport->phba->ndlp_lock, iflags); + spin_unlock_irqrestore(&ndlp->lock, iflags); } ndlp->nlp_flag &= ~NLP_UNREG_INP; } @@ -2529,9 +2655,10 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport, KERN_INFO, LOG_MBOX | LOG_DISCOVERY, "1438 UNREG cmpl deferred mbox x%x " - "on NPort x%x Data: x%x x%x %px\n", + "on NPort x%x Data: x%x x%x %px x%x x%x\n", ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, ndlp->nlp_defer_did, ndlp); + ndlp->nlp_flag, ndlp->nlp_defer_did, + ndlp, vport->load_flag, kref_read(&ndlp->kref)); if ((ndlp->nlp_flag & NLP_UNREG_INP) && (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) { @@ -2541,8 +2668,12 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { __lpfc_sli_rpi_release(vport, ndlp); } - if (vport->load_flag & FC_UNLOADING) - lpfc_nlp_put(ndlp); + + /* The unreg_login mailbox is complete and had a + * reference that has to be released. The PLOGI + * got its own ref. + */ + lpfc_nlp_put(ndlp); pmb->ctx_ndlp = NULL; } } @@ -2566,7 +2697,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * * This function is the unreg rpi mailbox completion handler. It * frees the memory resources associated with the completed mailbox - * command. An additional refrenece is put on the ndlp to prevent + * command. An additional reference is put on the ndlp to prevent * lpfc_nlp_release from freeing the rpi bit in the bitmask before * the unreg mailbox command completes, this routine puts the * reference back. @@ -2586,16 +2717,15 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) LPFC_SLI_INTF_IF_TYPE_2)) { if (ndlp) { lpfc_printf_vlog( - vport, KERN_INFO, LOG_MBOX | LOG_SLI, + vport, KERN_INFO, LOG_MBOX | LOG_SLI, "0010 UNREG_LOGIN vpi:%x " "rpi:%x DID:%x defer x%x flg x%x " - "map:%x %px\n", + "%px\n", vport->vpi, ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp->nlp_flag, - ndlp->nlp_usg_map, ndlp); + ndlp); ndlp->nlp_flag &= ~NLP_LOGO_ACC; - lpfc_nlp_put(ndlp); /* Check to see if there are any deferred * events to process @@ -2618,6 +2748,8 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { __lpfc_sli_rpi_release(vport, ndlp); } + + lpfc_nlp_put(ndlp); } } } @@ -2852,7 +2984,7 @@ lpfc_nvme_unsol_ls_handler(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) /* validate the source of the LS is logged in */ ndlp = lpfc_findnode_did(phba->pport, sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, @@ -4077,7 +4209,7 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) spin_lock_irq(&phba->hbalock); /* Next issue ABTS for everything on the txcmplq */ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); spin_unlock_irq(&phba->hbalock); } else { spin_lock_irq(&phba->hbalock); @@ -4086,7 +4218,7 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) /* Next issue ABTS for everything on the txcmplq */ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); spin_unlock_irq(&phba->hbalock); } @@ -7248,12 +7380,16 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, struct rqb_dmabuf *rqb_buffer; LIST_HEAD(rqb_buf_list); - spin_lock_irqsave(&phba->hbalock, flags); rqbp = hrq->rqbp; for (i = 0; i < count; i++) { + spin_lock_irqsave(&phba->hbalock, flags); /* IF RQ is already full, don't bother */ - if (rqbp->buffer_count + i >= rqbp->entry_count - 1) + if (rqbp->buffer_count + i >= rqbp->entry_count - 1) { + spin_unlock_irqrestore(&phba->hbalock, flags); break; + } + spin_unlock_irqrestore(&phba->hbalock, flags); + rqb_buffer = rqbp->rqb_alloc_buffer(phba); if (!rqb_buffer) break; @@ -7262,6 +7398,8 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, rqb_buffer->idx = idx; list_add_tail(&rqb_buffer->hbuf.list, &rqb_buf_list); } + + spin_lock_irqsave(&phba->hbalock, flags); while (!list_empty(&rqb_buf_list)) { list_remove_head(&rqb_buf_list, rqb_buffer, struct rqb_dmabuf, hbuf.list); @@ -9189,7 +9327,6 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) "1420 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } return 0; } @@ -10072,7 +10209,6 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, "2014 Invalid command 0x%x\n", iocbq->iocb.ulpCommand); return IOCB_ERROR; - break; } if (iocbq->iocb_flag & LPFC_IO_DIF_PASS) @@ -10094,6 +10230,96 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, } /** + * __lpfc_sli_issue_fcp_io_s3 - SLI3 device for sending fcp io iocb + * @phba: Pointer to HBA context object. + * @ring_number: SLI ring number to issue wqe on. + * @piocb: Pointer to command iocb. + * @flag: Flag indicating if this command can be put into txq. + * + * __lpfc_sli_issue_fcp_io_s3 is wrapper function to invoke lockless func to + * send an iocb command to an HBA with SLI-4 interface spec. + * + * This function takes the hbalock before invoking the lockless version. + * The function will return success after it successfully submit the wqe to + * firmware or after adding to the txq. + **/ +static int +__lpfc_sli_issue_fcp_io_s3(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + unsigned long iflags; + int rc; + + spin_lock_irqsave(&phba->hbalock, iflags); + rc = __lpfc_sli_issue_iocb_s3(phba, ring_number, piocb, flag); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + return rc; +} + +/** + * __lpfc_sli_issue_fcp_io_s4 - SLI4 device for sending fcp io wqe + * @phba: Pointer to HBA context object. + * @ring_number: SLI ring number to issue wqe on. + * @piocb: Pointer to command iocb. + * @flag: Flag indicating if this command can be put into txq. + * + * __lpfc_sli_issue_fcp_io_s4 is used by other functions in the driver to issue + * an wqe command to an HBA with SLI-4 interface spec. + * + * This function is a lockless version. The function will return success + * after it successfully submit the wqe to firmware or after adding to the + * txq. + **/ +static int +__lpfc_sli_issue_fcp_io_s4(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + int rc; + struct lpfc_io_buf *lpfc_cmd = + (struct lpfc_io_buf *)piocb->context1; + union lpfc_wqe128 *wqe = &piocb->wqe; + struct sli4_sge *sgl; + + /* 128 byte wqe support here */ + sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; + + if (phba->fcp_embed_io) { + struct fcp_cmnd *fcp_cmnd; + u32 *ptr; + + fcp_cmnd = lpfc_cmd->fcp_cmnd; + + /* Word 0-2 - FCP_CMND */ + wqe->generic.bde.tus.f.bdeFlags = + BUFF_TYPE_BDE_IMMED; + wqe->generic.bde.tus.f.bdeSize = sgl->sge_len; + wqe->generic.bde.addrHigh = 0; + wqe->generic.bde.addrLow = 88; /* Word 22 */ + + bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); + + /* Word 22-29 FCP CMND Payload */ + ptr = &wqe->words[22]; + memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd)); + } else { + /* Word 0-2 - Inline BDE */ + wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; + wqe->generic.bde.tus.f.bdeSize = sizeof(struct fcp_cmnd); + wqe->generic.bde.addrHigh = sgl->addr_hi; + wqe->generic.bde.addrLow = sgl->addr_lo; + + /* Word 10 */ + bf_set(wqe_dbde, &wqe->generic.wqe_com, 1); + bf_set(wqe_wqes, &wqe->generic.wqe_com, 0); + } + + rc = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, piocb); + return rc; +} + +/** * __lpfc_sli_issue_iocb_s4 - SLI4 device lockless ver of lpfc_sli_issue_iocb * @phba: Pointer to HBA context object. * @ring_number: SLI ring number to issue iocb on. @@ -10159,9 +10385,10 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, } } } - } else if (piocb->iocb_flag & LPFC_IO_FCP) + } else if (piocb->iocb_flag & LPFC_IO_FCP) { /* These IO's already have an XRI and a mapped sgl. */ sglq = NULL; + } else { /* * This is a continuation of a commandi,(CX) so this @@ -10189,6 +10416,25 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, return 0; } +/** + * lpfc_sli_issue_fcp_io - Wrapper func for issuing fcp i/o + * + * This routine wraps the actual fcp i/o function for issusing WQE for sli-4 + * or IOCB for sli-3 function. + * pointer from the lpfc_hba struct. + * + * Return codes: + * IOCB_ERROR - Error + * IOCB_SUCCESS - Success + * IOCB_BUSY - Busy + **/ +int +lpfc_sli_issue_fcp_io(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + return phba->__lpfc_sli_issue_fcp_io(phba, ring_number, piocb, flag); +} + /* * __lpfc_sli_issue_iocb - Wrapper func of lockless version for issuing iocb * @@ -10224,17 +10470,18 @@ lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) case LPFC_PCI_DEV_LP: phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s3; phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s3; + phba->__lpfc_sli_issue_fcp_io = __lpfc_sli_issue_fcp_io_s3; break; case LPFC_PCI_DEV_OC: phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s4; phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s4; + phba->__lpfc_sli_issue_fcp_io = __lpfc_sli_issue_fcp_io_s4; break; default: lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1419 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } phba->lpfc_get_iocb_from_iocbq = lpfc_get_iocb_from_iocbq; return 0; @@ -10364,6 +10611,32 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) return 0; } +static void +lpfc_sli_post_recovery_event(struct lpfc_hba *phba, + struct lpfc_nodelist *ndlp) +{ + unsigned long iflags; + struct lpfc_work_evt *evtp = &ndlp->recovery_evt; + + spin_lock_irqsave(&phba->hbalock, iflags); + if (!list_empty(&evtp->evt_listp)) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return; + } + + /* Incrementing the reference count until the queued work is done. */ + evtp->evt_arg1 = lpfc_nlp_get(ndlp); + if (!evtp->evt_arg1) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return; + } + evtp->evt = LPFC_EVT_RECOVER_PORT; + list_add_tail(&evtp->evt_listp, &phba->work_list); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + lpfc_worker_wake_up(phba); +} + /* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. * @phba: Pointer to HBA context object. * @iocbq: Pointer to iocb object. @@ -10397,7 +10670,7 @@ lpfc_sli_abts_err_handler(struct lpfc_hba *phba, if (!vport) goto err_exit; ndlp = lpfc_findnode_rpi(vport, rpi); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) goto err_exit; if (iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) @@ -10427,17 +10700,15 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct sli4_wcqe_xri_aborted *axri) { - struct lpfc_vport *vport; uint32_t ext_status = 0; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3115 Node Context not found, driver " "ignoring abts err event\n"); return; } - vport = ndlp->vport; lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "3116 Port generated FCP XRI ABORT event on " "vpi %d rpi %d xri x%x status 0x%x parameter x%x\n", @@ -10454,7 +10725,7 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, ext_status = axri->parameter & IOERR_PARAM_MASK; if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) && ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0))) - lpfc_sli_abts_recover_port(vport, ndlp); + lpfc_sli_post_recovery_event(phba, ndlp); } /** @@ -10908,7 +11179,8 @@ lpfc_sli_host_down(struct lpfc_vport *vport) &pring->txcmplq, list) { if (iocb->vport != vport) continue; - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, + NULL); } pring->flag = prev_pring_flag; } @@ -10935,7 +11207,8 @@ lpfc_sli_host_down(struct lpfc_vport *vport) &pring->txcmplq, list) { if (iocb->vport != vport) continue; - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, + NULL); } pring->flag = prev_pring_flag; } @@ -11324,35 +11597,37 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "x%x x%x x%x\n", irsp->ulpIoTag, irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout); + lpfc_nlp_put((struct lpfc_nodelist *)cmdiocb->context1); if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) lpfc_ct_free_iocb(phba, cmdiocb); else lpfc_els_free_iocb(phba, cmdiocb); - return; } /** - * lpfc_sli_abort_iotag_issue - Issue abort for a command iocb + * lpfc_sli_issue_abort_iotag - Abort function for a command iocb * @phba: Pointer to HBA context object. * @pring: Pointer to driver SLI ring object. * @cmdiocb: Pointer to driver command iocb object. + * @cmpl: completion function. + * + * This function issues an abort iocb for the provided command iocb. In case + * of unloading, the abort iocb will not be issued to commands on the ELS + * ring. Instead, the callback function shall be changed to those commands + * so that nothing happens when them finishes. This function is called with + * hbalock held andno ring_lock held (SLI4). The function returns IOCB_SUCCESS + * when the command iocb is an abort request. * - * This function issues an abort iocb for the provided command iocb down to - * the port. Other than the case the outstanding command iocb is an abort - * request, this function issues abort out unconditionally. This function is - * called with hbalock held. The function returns 0 when it fails due to - * memory allocation failure or when the command iocb is an abort request. - * The hbalock is asserted held in the code path calling this routine. **/ -static int -lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb) +int +lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *cmdiocb, void *cmpl) { struct lpfc_vport *vport = cmdiocb->vport; struct lpfc_iocbq *abtsiocbp; IOCB_t *icmd = NULL; IOCB_t *iabt = NULL; - int retval; + int retval = IOCB_ERROR; unsigned long iflags; struct lpfc_nodelist *ndlp; @@ -11365,12 +11640,33 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (icmd->ulpCommand == CMD_ABORT_XRI_CN || icmd->ulpCommand == CMD_CLOSE_XRI_CN || (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) - return 0; + return IOCB_ABORTING; + + if (!pring) { + if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) + cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; + else + cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; + return retval; + } + + /* + * If we're unloading, don't abort iocb on the ELS ring, but change + * the callback so that nothing happens when it finishes. + */ + if ((vport->load_flag & FC_UNLOADING) && + pring->ringno == LPFC_ELS_RING) { + if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) + cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; + else + cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; + return retval; + } /* issue ABTS for this IOCB based on iotag */ abtsiocbp = __lpfc_sli_get_iocbq(phba); if (abtsiocbp == NULL) - return 0; + return IOCB_NORESOURCE; /* This signals the response to set the correct status * before calling the completion handler @@ -11382,7 +11678,8 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt->un.acxri.abortContextTag = icmd->ulpContext; if (phba->sli_rev == LPFC_SLI_REV4) { iabt->un.acxri.abortIoTag = cmdiocb->sli4_xritag; - iabt->un.acxri.abortContextTag = cmdiocb->iotag; + if (pring->ringno == LPFC_ELS_RING) + iabt->un.acxri.abortContextTag = cmdiocb->iotag; } else { iabt->un.acxri.abortIoTag = icmd->ulpIoTag; if (pring->ringno == LPFC_ELS_RING) { @@ -11395,8 +11692,10 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocbp->hba_wqidx = cmdiocb->hba_wqidx; - if (cmdiocb->iocb_flag & LPFC_IO_FCP) + if (cmdiocb->iocb_flag & LPFC_IO_FCP) { + abtsiocbp->iocb_flag |= LPFC_IO_FCP; abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX; + } if (cmdiocb->iocb_flag & LPFC_IO_FOF) abtsiocbp->iocb_flag |= LPFC_IO_FOF; @@ -11405,20 +11704,16 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, else iabt->ulpCommand = CMD_CLOSE_XRI_CN; - abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; + if (cmpl) + abtsiocbp->iocb_cmpl = cmpl; + else + abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; abtsiocbp->vport = vport; - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "0339 Abort xri x%x, original iotag x%x, " - "abort cmd iotag x%x\n", - iabt->un.acxri.abortIoTag, - iabt->un.acxri.abortContextTag, - abtsiocbp->iotag); - if (phba->sli_rev == LPFC_SLI_REV4) { pring = lpfc_sli4_calc_ring(phba, abtsiocbp); if (unlikely(pring == NULL)) - return 0; + goto abort_iotag_exit; /* Note: both hbalock and ring_lock need to be set here */ spin_lock_irqsave(&pring->ring_lock, iflags); retval = __lpfc_sli_issue_iocb(phba, pring->ringno, @@ -11429,76 +11724,20 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, abtsiocbp, 0); } - if (retval) - __lpfc_sli_release_iocbq(phba, abtsiocbp); - - /* - * Caller to this routine should check for IOCB_ERROR - * and handle it properly. This routine no longer removes - * iocb off txcmplq and call compl in case of IOCB_ERROR. - */ - return retval; -} - -/** - * lpfc_sli_issue_abort_iotag - Abort function for a command iocb - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @cmdiocb: Pointer to driver command iocb object. - * - * This function issues an abort iocb for the provided command iocb. In case - * of unloading, the abort iocb will not be issued to commands on the ELS - * ring. Instead, the callback function shall be changed to those commands - * so that nothing happens when them finishes. This function is called with - * hbalock held. The function returns 0 when the command iocb is an abort - * request. - **/ -int -lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - int retval = IOCB_ERROR; - IOCB_t *icmd = NULL; - - lockdep_assert_held(&phba->hbalock); - - /* - * There are certain command types we don't want to abort. And we - * don't want to abort commands that are already in the process of - * being aborted. - */ - icmd = &cmdiocb->iocb; - if (icmd->ulpCommand == CMD_ABORT_XRI_CN || - icmd->ulpCommand == CMD_CLOSE_XRI_CN || - (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) - return 0; +abort_iotag_exit: - if (!pring) { - if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) - cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; - else - cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; - goto abort_iotag_exit; - } + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "0339 Abort xri x%x, original iotag x%x, " + "abort cmd iotag x%x retval x%x\n", + iabt->un.acxri.abortIoTag, + iabt->un.acxri.abortContextTag, + abtsiocbp->iotag, retval); - /* - * If we're unloading, don't abort iocb on the ELS ring, but change - * the callback so that nothing happens when it finishes. - */ - if ((vport->load_flag & FC_UNLOADING) && - (pring->ringno == LPFC_ELS_RING)) { - if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) - cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; - else - cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; - goto abort_iotag_exit; + if (retval) { + cmdiocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; + __lpfc_sli_release_iocbq(phba, abtsiocbp); } - /* Now, we try to issue the abort to the cmdiocb out */ - retval = lpfc_sli_abort_iotag_issue(phba, pring, cmdiocb); - -abort_iotag_exit: /* * Caller to this routine should check for IOCB_ERROR * and handle it properly. This routine no longer removes @@ -11643,6 +11882,33 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id, } /** + * lpfc_sli4_abort_fcp_cmpl - Completion handler function for aborted FCP IOCBs + * @phba: Pointer to HBA context object + * @cmdiocb: Pointer to command iocb object. + * @wcqe: pointer to the complete wcqe + * + * This function is called when an aborted FCP iocb completes. This + * function is called by the ring event handler with no lock held. + * This function frees the iocb. It is called for sli-4 adapters. + **/ +void +lpfc_sli4_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_wcqe_complete *wcqe) +{ + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3017 ABORT_XRI_CN completing on rpi x%x " + "original iotag x%x, abort cmd iotag x%x " + "status 0x%x, reason 0x%x\n", + cmdiocb->iocb.un.acxri.abortContextTag, + cmdiocb->iocb.un.acxri.abortIoTag, + cmdiocb->iotag, + (bf_get(lpfc_wcqe_c_status, wcqe) + & LPFC_IOCB_STATUS_MASK), + wcqe->parameter); + lpfc_sli_release_iocbq(phba, cmdiocb); +} + +/** * lpfc_sli_abort_fcp_cmpl - Completion handler function for aborted FCP IOCBs * @phba: Pointer to HBA context object * @cmdiocb: Pointer to command iocb object. @@ -11695,10 +11961,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, { struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *iocbq; - struct lpfc_iocbq *abtsiocb; - struct lpfc_sli_ring *pring_s4; - IOCB_t *cmd = NULL; int errcnt = 0, ret_val = 0; + unsigned long iflags; int i; /* all I/Os are in process of being flushed */ @@ -11712,62 +11976,12 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, abort_cmd) != 0) continue; - /* - * If the iocbq is already being aborted, don't take a second - * action, but do count it. - */ - if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED) - continue; - - /* issue ABTS for this IOCB based on iotag */ - abtsiocb = lpfc_sli_get_iocbq(phba); - if (abtsiocb == NULL) { - errcnt++; - continue; - } - - /* indicate the IO is being aborted by the driver. */ - iocbq->iocb_flag |= LPFC_DRIVER_ABORTED; - - cmd = &iocbq->iocb; - abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; - abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) - abtsiocb->iocb.un.acxri.abortIoTag = iocbq->sli4_xritag; - else - abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag; - abtsiocb->iocb.ulpLe = 1; - abtsiocb->iocb.ulpClass = cmd->ulpClass; - abtsiocb->vport = vport; - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocb->hba_wqidx = iocbq->hba_wqidx; - if (iocbq->iocb_flag & LPFC_IO_FCP) - abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; - if (iocbq->iocb_flag & LPFC_IO_FOF) - abtsiocb->iocb_flag |= LPFC_IO_FOF; - - if (lpfc_is_link_up(phba)) - abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; - else - abtsiocb->iocb.ulpCommand = CMD_CLOSE_XRI_CN; - - /* Setup callback routine and issue the command. */ - abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - if (phba->sli_rev == LPFC_SLI_REV4) { - pring_s4 = lpfc_sli4_calc_ring(phba, iocbq); - if (!pring_s4) - continue; - ret_val = lpfc_sli_issue_iocb(phba, pring_s4->ringno, - abtsiocb, 0); - } else - ret_val = lpfc_sli_issue_iocb(phba, pring->ringno, - abtsiocb, 0); - if (ret_val == IOCB_ERROR) { - lpfc_sli_release_iocbq(phba, abtsiocb); + spin_lock_irqsave(&phba->hbalock, iflags); + ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocbq, + lpfc_sli_abort_fcp_cmpl); + spin_unlock_irqrestore(&phba->hbalock, iflags); + if (ret_val != IOCB_SUCCESS) errcnt++; - continue; - } } return errcnt; @@ -13062,23 +13276,30 @@ lpfc_sli_intr_handler(int irq, void *dev_id) void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) { struct lpfc_cq_event *cq_event; + unsigned long iflags; /* First, declare the els xri abort event has been handled */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag &= ~ELS_XRI_ABORT_EVENT; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); + /* Now, handle all the els xri abort events */ + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); while (!list_empty(&phba->sli4_hba.sp_els_xri_aborted_work_queue)) { /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); list_remove_head(&phba->sli4_hba.sp_els_xri_aborted_work_queue, cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); /* Notify aborted XRI for ELS work queue */ lpfc_sli4_els_xri_aborted(phba, &cq_event->cqe.wcqe_axri); + /* Free the event processed back to the free pool */ lpfc_sli4_cq_event_release(phba, cq_event); + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); } + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); } /** @@ -13289,9 +13510,13 @@ lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) cq_event = lpfc_cq_event_setup(phba, mcqe, sizeof(struct lpfc_mcqe)); if (!cq_event) return false; - spin_lock_irqsave(&phba->hbalock, iflags); + + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); + /* Set the async event flag */ + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag |= ASYNC_EVENT; spin_unlock_irqrestore(&phba->hbalock, iflags); @@ -13375,6 +13600,12 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) pmbox->un.varWords[0], pmb); pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; pmb->ctx_buf = mp; + + /* No reference taken here. This is a default + * RPI reg/immediate unreg cycle. The reference was + * taken in the reg rpi path and is released when + * this mailbox completes. + */ pmb->ctx_ndlp = ndlp; pmb->vport = vport; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); @@ -13566,17 +13797,20 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, break; case LPFC_NVME_LS: /* NVME LS uses ELS resources */ case LPFC_ELS: - cq_event = lpfc_cq_event_setup( - phba, wcqe, sizeof(struct sli4_wcqe_xri_aborted)); - if (!cq_event) - return false; + cq_event = lpfc_cq_event_setup(phba, wcqe, sizeof(*wcqe)); + if (!cq_event) { + workposted = false; + break; + } cq_event->hdwq = cq->hdwq; - spin_lock_irqsave(&phba->hbalock, iflags); + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_els_xri_aborted_work_queue); /* Set the els xri abort event flag */ phba->hba_flag |= ELS_XRI_ABORT_EVENT; - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); workposted = true; break; default: @@ -14046,7 +14280,9 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, #endif if (cmdiocbq->iocb_cmpl == NULL) { if (cmdiocbq->wqe_cmpl) { - if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) { + /* For FCP the flag is cleared in wqe_cmpl */ + if (!(cmdiocbq->iocb_flag & LPFC_IO_FCP) && + cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) { spin_lock_irqsave(&phba->hbalock, iflags); cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED; spin_unlock_irqrestore(&phba->hbalock, iflags); @@ -14063,6 +14299,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, return; } + /* Only SLI4 non-IO commands stil use IOCB */ /* Fake the irspiocb and copy necessary response information */ lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe); @@ -15850,12 +16087,6 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, else wq_create_version = LPFC_Q_CREATE_VERSION_0; - - if (phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) - wq_create_version = LPFC_Q_CREATE_VERSION_1; - else - wq_create_version = LPFC_Q_CREATE_VERSION_0; - switch (wq_create_version) { case LPFC_Q_CREATE_VERSION_1: bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, @@ -17864,15 +18095,6 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, } /* Put ndlp onto pport node list */ lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, - "3275 Failed to active ndlp found " - "for oxid:x%x SID:x%x\n", oxid, sid); - return; - } } /* Allocate buffer for rsp iocb */ @@ -17897,6 +18119,10 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, icmd->ulpClass = CLASS3; icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; ctiocb->context1 = lpfc_nlp_get(ndlp); + if (!ctiocb->context1) { + lpfc_sli_release_iocbq(phba, ctiocb); + return; + } ctiocb->vport = phba->pport; ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; @@ -19840,7 +20066,6 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) struct lpfc_dmabuf *mp; struct lpfc_nodelist *ndlp; struct lpfc_nodelist *act_mbx_ndlp = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); LIST_HEAD(mbox_cmd_list); uint8_t restart_loop; @@ -19894,9 +20119,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) mb->mbox_flag |= LPFC_MBX_IMED_UNREG; restart_loop = 1; spin_unlock_irq(&phba->hbalock); - spin_lock(shost->host_lock); + spin_lock(&ndlp->lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); + spin_unlock(&ndlp->lock); spin_lock_irq(&phba->hbalock); break; } @@ -19918,9 +20143,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp; mb->ctx_ndlp = NULL; if (ndlp) { - spin_lock(shost->host_lock); + spin_lock(&ndlp->lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); + spin_unlock(&ndlp->lock); lpfc_nlp_put(ndlp); } } @@ -19929,9 +20154,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) /* Release the ndlp with the cleaned-up active mailbox command */ if (act_mbx_ndlp) { - spin_lock(shost->host_lock); + spin_lock(&act_mbx_ndlp->lock); act_mbx_ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); + spin_unlock(&act_mbx_ndlp->lock); lpfc_nlp_put(act_mbx_ndlp); } } @@ -20213,7 +20438,8 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, } /* NVME_FCREQ and NVME_ABTS requests */ - if (pwqe->iocb_flag & LPFC_IO_NVME) { + if (pwqe->iocb_flag & LPFC_IO_NVME || + pwqe->iocb_flag & LPFC_IO_FCP) { /* Get the IO distribution (hba_wqidx) for WQ assignment. */ wq = qp->io_wq; pring = wq->pring; @@ -20266,6 +20492,88 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, return WQE_ERROR; } +/** + * lpfc_sli4_issue_abort_iotag - SLI-4 WQE init & issue for the Abort + * @phba: Pointer to HBA context object. + * @cmdiocb: Pointer to driver command iocb object. + * @cmpl: completion function. + * + * Fill the appropriate fields for the abort WQE and call + * internal routine lpfc_sli4_issue_wqe to send the WQE + * This function is called with hbalock held and no ring_lock held. + * + * RETURNS 0 - SUCCESS + **/ + +int +lpfc_sli4_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + void *cmpl) +{ + struct lpfc_vport *vport = cmdiocb->vport; + struct lpfc_iocbq *abtsiocb = NULL; + union lpfc_wqe128 *abtswqe; + struct lpfc_io_buf *lpfc_cmd; + int retval = IOCB_ERROR; + u16 xritag = cmdiocb->sli4_xritag; + + /* + * The scsi command can not be in txq and it is in flight because the + * pCmd is still pointing at the SCSI command we have to abort. There + * is no need to search the txcmplq. Just send an abort to the FW. + */ + + abtsiocb = __lpfc_sli_get_iocbq(phba); + if (!abtsiocb) + return WQE_NORESOURCE; + + /* Indicate the IO is being aborted by the driver. */ + cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; + + abtswqe = &abtsiocb->wqe; + memset(abtswqe, 0, sizeof(*abtswqe)); + + if (lpfc_is_link_up(phba)) + bf_set(abort_cmd_ia, &abtswqe->abort_cmd, 1); + else + bf_set(abort_cmd_ia, &abtswqe->abort_cmd, 0); + bf_set(abort_cmd_criteria, &abtswqe->abort_cmd, T_XRI_TAG); + abtswqe->abort_cmd.rsrvd5 = 0; + abtswqe->abort_cmd.wqe_com.abort_tag = xritag; + bf_set(wqe_reqtag, &abtswqe->abort_cmd.wqe_com, abtsiocb->iotag); + bf_set(wqe_cmnd, &abtswqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); + bf_set(wqe_xri_tag, &abtswqe->generic.wqe_com, 0); + bf_set(wqe_qosd, &abtswqe->abort_cmd.wqe_com, 1); + bf_set(wqe_lenloc, &abtswqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); + bf_set(wqe_cmd_type, &abtswqe->abort_cmd.wqe_com, OTHER_COMMAND); + + /* ABTS WQE must go to the same WQ as the WQE to be aborted */ + abtsiocb->hba_wqidx = cmdiocb->hba_wqidx; + abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; + if (cmdiocb->iocb_flag & LPFC_IO_FCP) + abtsiocb->iocb_flag |= LPFC_IO_FCP; + if (cmdiocb->iocb_flag & LPFC_IO_NVME) + abtsiocb->iocb_flag |= LPFC_IO_NVME; + if (cmdiocb->iocb_flag & LPFC_IO_FOF) + abtsiocb->iocb_flag |= LPFC_IO_FOF; + abtsiocb->vport = vport; + abtsiocb->wqe_cmpl = cmpl; + + lpfc_cmd = container_of(cmdiocb, struct lpfc_io_buf, cur_iocbq); + retval = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, abtsiocb); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "0359 Abort xri x%x, original iotag x%x, " + "abort cmd iotag x%x retval x%x\n", + xritag, cmdiocb->iotag, abtsiocb->iotag, retval); + + if (retval) { + cmdiocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; + __lpfc_sli_release_iocbq(phba, abtsiocb); + } + + return retval; +} + #ifdef LPFC_MXP_STAT /** * lpfc_snapshot_mxp - Snapshot pbl, pvt and busy count diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 93d976ea8c5d..4f6936014ff5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -130,6 +130,9 @@ struct lpfc_iocbq { #define IOCB_BUSY 1 #define IOCB_ERROR 2 #define IOCB_TIMEDOUT 3 +#define IOCB_ABORTED 4 +#define IOCB_ABORTING 5 +#define IOCB_NORESOURCE 6 #define SLI_WQE_RET_WQE 1 /* Return WQE if cmd ring full */ @@ -138,6 +141,8 @@ struct lpfc_iocbq { #define WQE_ERROR 2 #define WQE_TIMEDOUT 3 #define WQE_ABORTED 4 +#define WQE_ABORTING 5 +#define WQE_NORESOURCE 6 #define LPFC_MBX_WAKE 1 #define LPFC_MBX_IMED_UNREG 2 diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index a966cdeb52ee..26f19c95380f 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -549,6 +549,14 @@ struct lpfc_pc_sli4_params { uint32_t hdr_pp_align; uint32_t sgl_pages_max; uint32_t sgl_pp_align; + uint32_t mib_size; + uint16_t mi_ver; +#define LPFC_MIB1_SUPPORT 1 +#define LPFC_MIB2_SUPPORT 2 +#define LPFC_MIB3_SUPPORT 3 + uint16_t mi_value; +#define LPFC_DFLT_MIB_VAL 2 + uint8_t mib_bde_cnt; uint8_t cqv; uint8_t mqv; uint8_t wqv; @@ -920,8 +928,9 @@ struct lpfc_sli4_hba { struct list_head sp_queue_event; struct list_head sp_cqe_event_pool; struct list_head sp_asynce_work_queue; - struct list_head sp_fcp_xri_aborted_work_queue; + spinlock_t asynce_list_lock; /* protect sp_asynce_work_queue list */ struct list_head sp_els_xri_aborted_work_queue; + spinlock_t els_xri_abrt_list_lock; /* protect els_xri_aborted list */ struct list_head sp_unsol_work_queue; struct lpfc_sli4_link link_state; struct lpfc_sli4_lnk_info lnk_info; @@ -1103,8 +1112,7 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *); void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *); int lpfc_sli4_resume_rpi(struct lpfc_nodelist *, void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *); -void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *); -void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *); +void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba); void lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri, struct lpfc_io_buf *lpfc_ncmd); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index c657abf22b75..234dca60995b 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "12.8.0.4" +#define LPFC_DRIVER_VERSION "12.8.0.6" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ @@ -32,6 +32,6 @@ #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright (C) 2017-2019 Broadcom. All Rights " \ +#define LPFC_COPYRIGHT "Copyright (C) 2017-2020 Broadcom. All Rights " \ "Reserved. The term \"Broadcom\" refers to Broadcom Inc. " \ "and/or its subsidiaries." diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index aa4e451d5dc1..a99fdfba7d27 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -462,7 +462,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) * up and ready to FDISC. */ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { lpfc_set_disctmo(vport); @@ -495,8 +495,7 @@ disable_vport(struct fc_vport *fc_vport) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && phba->link_state >= LPFC_LINK_UP) { + if (ndlp && phba->link_state >= LPFC_LINK_UP) { vport->unreg_vpi_cmpl = VPORT_INVAL; timeout = msecs_to_jiffies(phba->fc_ratov * 2000); if (!lpfc_issue_els_npiv_logo(vport, ndlp)) @@ -510,8 +509,6 @@ disable_vport(struct fc_vport *fc_vport) * calling lpfc_cleanup_rpis(vport, 1) */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; lpfc_disc_state_machine(vport, ndlp, NULL, @@ -568,8 +565,7 @@ enable_vport(struct fc_vport *fc_vport) * up and ready to FDISC. */ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { lpfc_set_disctmo(vport); lpfc_initial_fdisc(vport); @@ -597,16 +593,14 @@ lpfc_vport_disable(struct fc_vport *fc_vport, bool disable) return enable_vport(fc_vport); } - int lpfc_vport_delete(struct fc_vport *fc_vport) { struct lpfc_nodelist *ndlp = NULL; struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; + struct lpfc_hba *phba = vport->phba; long timeout; - bool ns_ndlp_referenced = false; if (vport->port_type == LPFC_PHYSICAL_PORT) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -623,9 +617,11 @@ lpfc_vport_delete(struct fc_vport *fc_vport) "static vport.\n"); return VPORT_ERROR; } + spin_lock_irq(&phba->hbalock); vport->load_flag |= FC_UNLOADING; spin_unlock_irq(&phba->hbalock); + /* * If we are not unloading the driver then prevent the vport_delete * from happening until after this vport's discovery is finished. @@ -653,64 +649,22 @@ lpfc_vport_delete(struct fc_vport *fc_vport) return VPORT_INVAL; lpfc_free_sysfs_attr(vport); - lpfc_debugfs_terminate(vport); - /* - * The call to fc_remove_host might release the NameServer ndlp. Since - * we might need to use the ndlp to send the DA_ID CT command, - * increment the reference for the NameServer ndlp to prevent it from - * being released. - */ - ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - lpfc_nlp_get(ndlp); - ns_ndlp_referenced = true; - } - - /* Remove FC host and then SCSI host with the vport */ + /* Remove FC host to break driver binding. */ fc_remove_host(shost); scsi_remove_host(shost); - ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - - /* In case of driver unload, we shall not perform fabric logo as the - * worker thread already stopped at this stage and, in this case, we - * can safely skip the fabric logo. - */ - if (phba->pport->load_flag & FC_UNLOADING) { - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && - phba->link_state >= LPFC_LINK_UP) { - /* First look for the Fabric ndlp */ - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) - goto skip_logo; - else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto skip_logo; - } - /* Remove ndlp from vport npld list */ - lpfc_dequeue_node(vport, ndlp); - - /* Indicate free memory when release */ - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - /* Kick off release ndlp when it can be safely done */ - lpfc_nlp_put(ndlp); - } + /* Send the DA_ID and Fabric LOGO to cleanup Nameserver entries. */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) goto skip_logo; - } - /* Otherwise, we will perform fabric logo as needed */ - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && phba->link_state >= LPFC_LINK_UP && phba->fc_topology != LPFC_TOPOLOGY_LOOP) { if (vport->cfg_enable_da_id) { + /* Send DA_ID and wait for a completion. */ timeout = msecs_to_jiffies(phba->fc_ratov * 2000); if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0)) while (vport->ct_flags && timeout) @@ -721,47 +675,19 @@ lpfc_vport_delete(struct fc_vport *fc_vport) "1829 CT command failed to " "delete objects on fabric\n"); } - /* First look for the Fabric ndlp */ - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) { - /* Cannot find existing Fabric ndlp, allocate one */ - ndlp = lpfc_nlp_init(vport, Fabric_DID); - if (!ndlp) - goto skip_logo; - /* Indicate free memory when release */ - NLP_SET_FREE_REQ(ndlp); - } else { - if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto skip_logo; - } - - /* Remove ndlp from vport list */ - lpfc_dequeue_node(vport, ndlp); - spin_lock_irq(&phba->ndlp_lock); - if (!NLP_CHK_FREE_REQ(ndlp)) - /* Indicate free memory when release */ - NLP_SET_FREE_REQ(ndlp); - else { - /* Skip this if ndlp is already in free mode */ - spin_unlock_irq(&phba->ndlp_lock); - goto skip_logo; - } - spin_unlock_irq(&phba->ndlp_lock); - } /* * If the vpi is not registered, then a valid FDISC doesn't * exist and there is no need for a ELS LOGO. Just cleanup * the ndlp. */ - if (!(vport->vpi_state & LPFC_VPI_REGISTERED)) { - lpfc_nlp_put(ndlp); + if (!(vport->vpi_state & LPFC_VPI_REGISTERED)) goto skip_logo; - } + /* Issue a Fabric LOGO to cleanup fabric resources. */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) + goto skip_logo; vport->unreg_vpi_cmpl = VPORT_INVAL; timeout = msecs_to_jiffies(phba->fc_ratov * 2000); if (!lpfc_issue_els_npiv_logo(vport, ndlp)) @@ -774,18 +700,10 @@ lpfc_vport_delete(struct fc_vport *fc_vport) skip_logo: - /* - * If the NameServer ndlp has been incremented to allow the DA_ID CT - * command to be sent, decrement the ndlp now. - */ - if (ns_ndlp_referenced) { - ndlp = lpfc_findnode_did(vport, NameServer_DID); - lpfc_nlp_put(ndlp); - } - lpfc_cleanup(vport); - lpfc_sli_host_down(vport); + /* Remove scsi host now. The nodes are cleaned up. */ + lpfc_sli_host_down(vport); lpfc_stop_vport_timers(vport); if (!(phba->pport->load_flag & FC_UNLOADING)) { @@ -865,8 +783,6 @@ lpfc_vport_reset_stat_data(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->lat_data) memset(ndlp->lat_data, 0, LPFC_MAX_BUCKET_COUNT * sizeof(struct lpfc_scsicmd_bkt)); @@ -887,8 +803,6 @@ lpfc_alloc_bucket(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; kfree(ndlp->lat_data); ndlp->lat_data = NULL; @@ -921,8 +835,6 @@ lpfc_free_bucket(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; kfree(ndlp->lat_data); ndlp->lat_data = NULL; diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index b5dde9d0d054..5c808fbc6ce2 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -285,7 +285,7 @@ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_DRQ | BASR_PHASE_MATCH, - BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { + BASR_DRQ | BASR_PHASE_MATCH, 0)) { int bytes; if (macintosh_config->ident == MAC_MODEL_IIFX) @@ -304,7 +304,7 @@ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, BUS_AND_STATUS_REG, BASR_ACK, - BASR_ACK, HZ / 64) < 0) + BASR_ACK, 0) < 0) scmd_printk(KERN_DEBUG, hostdata->connected, "%s: !REQ and !ACK\n", __func__); if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) @@ -344,7 +344,7 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_DRQ | BASR_PHASE_MATCH, - BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { + BASR_DRQ | BASR_PHASE_MATCH, 0)) { int bytes; if (macintosh_config->ident == MAC_MODEL_IIFX) @@ -362,7 +362,7 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG, TCR_LAST_BYTE_SENT, TCR_LAST_BYTE_SENT, - HZ / 64) < 0) { + 0) < 0) { scmd_printk(KERN_ERR, hostdata->connected, "%s: Last Byte Sent timeout\n", __func__); result = -1; @@ -372,7 +372,7 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, BUS_AND_STATUS_REG, BASR_ACK, - BASR_ACK, HZ / 64) < 0) + BASR_ACK, 0) < 0) scmd_printk(KERN_DEBUG, hostdata->connected, "%s: !REQ and !ACK\n", __func__); if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 5e4137f10e0e..0f808d63580e 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2605,7 +2605,6 @@ struct megasas_aen { u32 class_locale_word; } __attribute__ ((packed)); -#ifdef CONFIG_COMPAT struct compat_megasas_iocpacket { u16 host_no; u16 __pad1; @@ -2621,7 +2620,6 @@ struct compat_megasas_iocpacket { } __attribute__ ((packed)); #define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket) -#endif #define MEGASAS_IOC_FIRMWARE _IOWR('M', 1, struct megasas_iocpacket) #define MEGASAS_IOC_GET_AEN _IOW('M', 3, struct megasas_aen) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index e158d3d62056..6e4bf05c6d77 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -7554,25 +7554,23 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, megasas_return_cmd(instance, cmd); } -#ifdef CONFIG_PM /** * megasas_suspend - driver suspend entry point - * @pdev: PCI device structure - * @state: PCI power state to suspend routine + * @dev: Device structure */ -static int -megasas_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused +megasas_suspend(struct device *dev) { struct megasas_instance *instance; - instance = pci_get_drvdata(pdev); + instance = dev_get_drvdata(dev); if (!instance) return 0; instance->unload = 1; - dev_info(&pdev->dev, "%s is called\n", __func__); + dev_info(dev, "%s is called\n", __func__); /* Shutdown SR-IOV heartbeat timer */ if (instance->requestorId && !instance->skip_heartbeat_timer_del) @@ -7602,48 +7600,29 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) if (instance->msix_vectors) pci_free_irq_vectors(instance->pdev); - pci_save_state(pdev); - pci_disable_device(pdev); - - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } /** * megasas_resume- driver resume entry point - * @pdev: PCI device structure + * @dev: Device structure */ -static int -megasas_resume(struct pci_dev *pdev) +static int __maybe_unused +megasas_resume(struct device *dev) { int rval; struct Scsi_Host *host; struct megasas_instance *instance; u32 status_reg; - instance = pci_get_drvdata(pdev); + instance = dev_get_drvdata(dev); if (!instance) return 0; host = instance->host; - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - dev_info(&pdev->dev, "%s is called\n", __func__); - /* - * PCI prepping: enable device set bus mastering and dma mask - */ - rval = pci_enable_device_mem(pdev); - if (rval) { - dev_err(&pdev->dev, "Enable device failed\n"); - return rval; - } - - pci_set_master(pdev); + dev_info(dev, "%s is called\n", __func__); /* * We expect the FW state to be READY @@ -7769,14 +7748,8 @@ fail_reenable_msix: fail_set_dma_mask: fail_ready_state: - pci_disable_device(pdev); - return -ENODEV; } -#else -#define megasas_suspend NULL -#define megasas_resume NULL -#endif static inline int megasas_wait_for_adapter_operational(struct megasas_instance *instance) @@ -7946,7 +7919,7 @@ skip_firing_dcmds: /** * megasas_shutdown - Shutdown entry point - * @pdev: Generic device structure + * @pdev: PCI device structure */ static void megasas_shutdown(struct pci_dev *pdev) { @@ -8095,7 +8068,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, int error = 0, i; void *sense = NULL; dma_addr_t sense_handle; - unsigned long *sense_ptr; + void *sense_ptr; u32 opcode = 0; int ret = DCMD_SUCCESS; @@ -8218,6 +8191,13 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, } if (ioc->sense_len) { + /* make sure the pointer is part of the frame */ + if (ioc->sense_off > + (sizeof(union megasas_frame) - sizeof(__le64))) { + error = -EINVAL; + goto out; + } + sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len, &sense_handle, GFP_KERNEL); if (!sense) { @@ -8225,12 +8205,11 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, goto out; } - sense_ptr = - (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off); + sense_ptr = (void *)cmd->frame + ioc->sense_off; if (instance->consistent_mask_64bit) - *sense_ptr = cpu_to_le64(sense_handle); + put_unaligned_le64(sense_handle, sense_ptr); else - *sense_ptr = cpu_to_le32(sense_handle); + put_unaligned_le32(sense_handle, sense_ptr); } /* @@ -8274,16 +8253,19 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, * copy out the sense */ if (ioc->sense_len) { + void __user *uptr; /* * sense_ptr points to the location that has the user * sense buffer address */ - sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw + - ioc->sense_off); + sense_ptr = (void *)ioc->frame.raw + ioc->sense_off; + if (in_compat_syscall()) + uptr = compat_ptr(get_unaligned((compat_uptr_t *) + sense_ptr)); + else + uptr = get_unaligned((void __user **)sense_ptr); - if (copy_to_user((void __user *)((unsigned long) - get_unaligned((unsigned long *)sense_ptr)), - sense, ioc->sense_len)) { + if (copy_to_user(uptr, sense, ioc->sense_len)) { dev_err(&instance->pdev->dev, "Failed to copy out to user " "sense data\n"); error = -EFAULT; @@ -8326,6 +8308,38 @@ out: return error; } +static struct megasas_iocpacket * +megasas_compat_iocpacket_get_user(void __user *arg) +{ + struct megasas_iocpacket *ioc; + struct compat_megasas_iocpacket __user *cioc = arg; + size_t size; + int err = -EFAULT; + int i; + + ioc = kzalloc(sizeof(*ioc), GFP_KERNEL); + if (!ioc) + return ERR_PTR(-ENOMEM); + size = offsetof(struct megasas_iocpacket, frame) + sizeof(ioc->frame); + if (copy_from_user(ioc, arg, size)) + goto out; + + for (i = 0; i < MAX_IOCTL_SGE; i++) { + compat_uptr_t iov_base; + + if (get_user(iov_base, &cioc->sgl[i].iov_base) || + get_user(ioc->sgl[i].iov_len, &cioc->sgl[i].iov_len)) + goto out; + + ioc->sgl[i].iov_base = compat_ptr(iov_base); + } + + return ioc; +out: + kfree(ioc); + return ERR_PTR(err); +} + static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) { struct megasas_iocpacket __user *user_ioc = @@ -8334,7 +8348,11 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) struct megasas_instance *instance; int error; - ioc = memdup_user(user_ioc, sizeof(*ioc)); + if (in_compat_syscall()) + ioc = megasas_compat_iocpacket_get_user(user_ioc); + else + ioc = memdup_user(user_ioc, sizeof(struct megasas_iocpacket)); + if (IS_ERR(ioc)) return PTR_ERR(ioc); @@ -8439,78 +8457,13 @@ megasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT -static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) -{ - struct compat_megasas_iocpacket __user *cioc = - (struct compat_megasas_iocpacket __user *)arg; - struct megasas_iocpacket __user *ioc = - compat_alloc_user_space(sizeof(struct megasas_iocpacket)); - int i; - int error = 0; - compat_uptr_t ptr; - u32 local_sense_off; - u32 local_sense_len; - u32 user_sense_off; - - if (clear_user(ioc, sizeof(*ioc))) - return -EFAULT; - - if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) || - copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) || - copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) || - copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) || - copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) || - copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32))) - return -EFAULT; - - /* - * The sense_ptr is used in megasas_mgmt_fw_ioctl only when - * sense_len is not null, so prepare the 64bit value under - * the same condition. - */ - if (get_user(local_sense_off, &ioc->sense_off) || - get_user(local_sense_len, &ioc->sense_len) || - get_user(user_sense_off, &cioc->sense_off)) - return -EFAULT; - - if (local_sense_off != user_sense_off) - return -EINVAL; - - if (local_sense_len) { - void __user **sense_ioc_ptr = - (void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off); - compat_uptr_t *sense_cioc_ptr = - (compat_uptr_t *)(((unsigned long)&cioc->frame.raw) + user_sense_off); - if (get_user(ptr, sense_cioc_ptr) || - put_user(compat_ptr(ptr), sense_ioc_ptr)) - return -EFAULT; - } - - for (i = 0; i < MAX_IOCTL_SGE; i++) { - if (get_user(ptr, &cioc->sgl[i].iov_base) || - put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) || - copy_in_user(&ioc->sgl[i].iov_len, - &cioc->sgl[i].iov_len, sizeof(compat_size_t))) - return -EFAULT; - } - - error = megasas_mgmt_ioctl_fw(file, (unsigned long)ioc); - - if (copy_in_user(&cioc->frame.hdr.cmd_status, - &ioc->frame.hdr.cmd_status, sizeof(u8))) { - printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n"); - return -EFAULT; - } - return error; -} - static long megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case MEGASAS_IOC_FIRMWARE32: - return megasas_mgmt_compat_ioctl_fw(file, arg); + return megasas_mgmt_ioctl_fw(file, arg); case MEGASAS_IOC_GET_AEN: return megasas_mgmt_ioctl_aen(file, arg); } @@ -8534,6 +8487,8 @@ static const struct file_operations megasas_mgmt_fops = { .llseek = noop_llseek, }; +static SIMPLE_DEV_PM_OPS(megasas_pm_ops, megasas_suspend, megasas_resume); + /* * PCI hotplug support registration structure */ @@ -8543,8 +8498,7 @@ static struct pci_driver megasas_pci_driver = { .id_table = megasas_pci_table, .probe = megasas_probe_one, .remove = megasas_detach_one, - .suspend = megasas_suspend, - .resume = megasas_resume, + .driver.pm = &megasas_pm_ops, .shutdown = megasas_shutdown, }; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index bb940cbcbb5d..969baf4cd3f5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -597,6 +597,71 @@ static int mpt3sas_remove_dead_ioc_func(void *arg) } /** + * _base_sync_drv_fw_timestamp - Sync Drive-Fw TimeStamp. + * @ioc: Per Adapter Object + * + * Return nothing. + */ +static void _base_sync_drv_fw_timestamp(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi26IoUnitControlRequest_t *mpi_request; + Mpi26IoUnitControlReply_t *mpi_reply; + u16 smid; + ktime_t current_time; + u64 TimeStamp = 0; + u8 issue_reset = 0; + + mutex_lock(&ioc->scsih_cmds.mutex); + if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { + ioc_err(ioc, "scsih_cmd in use %s\n", __func__); + goto out; + } + ioc->scsih_cmds.status = MPT3_CMD_PENDING; + smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx); + if (!smid) { + ioc_err(ioc, "Failed obtaining a smid %s\n", __func__); + ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; + goto out; + } + mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); + ioc->scsih_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi26IoUnitControlRequest_t)); + mpi_request->Function = MPI2_FUNCTION_IO_UNIT_CONTROL; + mpi_request->Operation = MPI26_CTRL_OP_SET_IOC_PARAMETER; + mpi_request->IOCParameter = MPI26_SET_IOC_PARAMETER_SYNC_TIMESTAMP; + current_time = ktime_get_real(); + TimeStamp = ktime_to_ms(current_time); + mpi_request->Reserved7 = cpu_to_le32(TimeStamp & 0xFFFFFFFF); + mpi_request->IOCParameterValue = cpu_to_le32(TimeStamp >> 32); + init_completion(&ioc->scsih_cmds.done); + ioc->put_smid_default(ioc, smid); + dinitprintk(ioc, ioc_info(ioc, + "Io Unit Control Sync TimeStamp (sending), @time %lld ms\n", + TimeStamp)); + wait_for_completion_timeout(&ioc->scsih_cmds.done, + MPT3SAS_TIMESYNC_TIMEOUT_SECONDS*HZ); + if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { + mpt3sas_check_cmd_timeout(ioc, + ioc->scsih_cmds.status, mpi_request, + sizeof(Mpi2SasIoUnitControlRequest_t)/4, issue_reset); + goto issue_host_reset; + } + if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { + mpi_reply = ioc->scsih_cmds.reply; + dinitprintk(ioc, ioc_info(ioc, + "Io Unit Control sync timestamp (complete): ioc_status(0x%04x), loginfo(0x%08x)\n", + le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo))); + } +issue_host_reset: + if (issue_reset) + mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); + ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; +out: + mutex_unlock(&ioc->scsih_cmds.mutex); +} + +/** * _base_fault_reset_work - workq handling ioc fault conditions * @work: input argument, used to derive ioc * @@ -720,7 +785,11 @@ _base_fault_reset_work(struct work_struct *work) return; /* don't rearm timer */ } ioc->ioc_coredump_loop = 0; - + if (ioc->time_sync_interval && + ++ioc->timestamp_update_count >= ioc->time_sync_interval) { + ioc->timestamp_update_count = 0; + _base_sync_drv_fw_timestamp(ioc); + } spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); rearm_timer: if (ioc->fault_reset_work_q) @@ -744,6 +813,7 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) if (ioc->fault_reset_work_q) return; + ioc->timestamp_update_count = 0; /* initialize fault polling */ INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); @@ -905,6 +975,20 @@ _base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) return; + /* + * Older Firmware version doesn't support driver trigger pages. + * So, skip displaying 'config invalid type' type + * of error message. + */ + if (request_hdr->Function == MPI2_FUNCTION_CONFIG) { + Mpi2ConfigRequest_t *rqst = (Mpi2ConfigRequest_t *)request_hdr; + + if ((rqst->ExtPageType == + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER) && + !(ioc->logging_level & MPT_DEBUG_CONFIG)) { + return; + } + } switch (ioc_status) { @@ -4721,6 +4805,311 @@ _base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc) } /** + * _base_get_event_diag_triggers - get event diag trigger values from + * persistent pages + * @ioc : per adapter object + * + * Return nothing. + */ +static void +_base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi26DriverTriggerPage2_t trigger_pg2; + struct SL_WH_EVENT_TRIGGER_T *event_tg; + MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY *mpi_event_tg; + Mpi2ConfigReply_t mpi_reply; + int r = 0, i = 0; + u16 count = 0; + u16 ioc_status; + + r = mpt3sas_config_get_driver_trigger_pg2(ioc, &mpi_reply, + &trigger_pg2); + if (r) + return; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dinitprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg2, ioc_status(0x%04x)\n", + __func__, ioc_status)); + return; + } + + if (le16_to_cpu(trigger_pg2.NumMPIEventTrigger)) { + count = le16_to_cpu(trigger_pg2.NumMPIEventTrigger); + count = min_t(u16, NUM_VALID_ENTRIES, count); + ioc->diag_trigger_event.ValidEntries = count; + + event_tg = &ioc->diag_trigger_event.EventTriggerEntry[0]; + mpi_event_tg = &trigger_pg2.MPIEventTriggers[0]; + for (i = 0; i < count; i++) { + event_tg->EventValue = le16_to_cpu( + mpi_event_tg->MPIEventCode); + event_tg->LogEntryQualifier = le16_to_cpu( + mpi_event_tg->MPIEventCodeSpecific); + event_tg++; + mpi_event_tg++; + } + } +} + +/** + * _base_get_scsi_diag_triggers - get scsi diag trigger values from + * persistent pages + * @ioc : per adapter object + * + * Return nothing. + */ +static void +_base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi26DriverTriggerPage3_t trigger_pg3; + struct SL_WH_SCSI_TRIGGER_T *scsi_tg; + MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY *mpi_scsi_tg; + Mpi2ConfigReply_t mpi_reply; + int r = 0, i = 0; + u16 count = 0; + u16 ioc_status; + + r = mpt3sas_config_get_driver_trigger_pg3(ioc, &mpi_reply, + &trigger_pg3); + if (r) + return; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dinitprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg3, ioc_status(0x%04x)\n", + __func__, ioc_status)); + return; + } + + if (le16_to_cpu(trigger_pg3.NumSCSISenseTrigger)) { + count = le16_to_cpu(trigger_pg3.NumSCSISenseTrigger); + count = min_t(u16, NUM_VALID_ENTRIES, count); + ioc->diag_trigger_scsi.ValidEntries = count; + + scsi_tg = &ioc->diag_trigger_scsi.SCSITriggerEntry[0]; + mpi_scsi_tg = &trigger_pg3.SCSISenseTriggers[0]; + for (i = 0; i < count; i++) { + scsi_tg->ASCQ = mpi_scsi_tg->ASCQ; + scsi_tg->ASC = mpi_scsi_tg->ASC; + scsi_tg->SenseKey = mpi_scsi_tg->SenseKey; + + scsi_tg++; + mpi_scsi_tg++; + } + } +} + +/** + * _base_get_mpi_diag_triggers - get mpi diag trigger values from + * persistent pages + * @ioc : per adapter object + * + * Return nothing. + */ +static void +_base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi26DriverTriggerPage4_t trigger_pg4; + struct SL_WH_MPI_TRIGGER_T *status_tg; + MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY *mpi_status_tg; + Mpi2ConfigReply_t mpi_reply; + int r = 0, i = 0; + u16 count = 0; + u16 ioc_status; + + r = mpt3sas_config_get_driver_trigger_pg4(ioc, &mpi_reply, + &trigger_pg4); + if (r) + return; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dinitprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg4, ioc_status(0x%04x)\n", + __func__, ioc_status)); + return; + } + + if (le16_to_cpu(trigger_pg4.NumIOCStatusLogInfoTrigger)) { + count = le16_to_cpu(trigger_pg4.NumIOCStatusLogInfoTrigger); + count = min_t(u16, NUM_VALID_ENTRIES, count); + ioc->diag_trigger_mpi.ValidEntries = count; + + status_tg = &ioc->diag_trigger_mpi.MPITriggerEntry[0]; + mpi_status_tg = &trigger_pg4.IOCStatusLoginfoTriggers[0]; + + for (i = 0; i < count; i++) { + status_tg->IOCStatus = le16_to_cpu( + mpi_status_tg->IOCStatus); + status_tg->IocLogInfo = le32_to_cpu( + mpi_status_tg->LogInfo); + + status_tg++; + mpi_status_tg++; + } + } +} + +/** + * _base_get_master_diag_triggers - get master diag trigger values from + * persistent pages + * @ioc : per adapter object + * + * Return nothing. + */ +static void +_base_get_master_diag_triggers(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi26DriverTriggerPage1_t trigger_pg1; + Mpi2ConfigReply_t mpi_reply; + int r; + u16 ioc_status; + + r = mpt3sas_config_get_driver_trigger_pg1(ioc, &mpi_reply, + &trigger_pg1); + if (r) + return; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dinitprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg1, ioc_status(0x%04x)\n", + __func__, ioc_status)); + return; + } + + if (le16_to_cpu(trigger_pg1.NumMasterTrigger)) + ioc->diag_trigger_master.MasterData |= + le32_to_cpu( + trigger_pg1.MasterTriggers[0].MasterTriggerFlags); +} + +/** + * _base_check_for_trigger_pages_support - checks whether HBA FW supports + * driver trigger pages or not + * @ioc : per adapter object + * + * Returns trigger flags mask if HBA FW supports driver trigger pages, + * otherwise returns EFAULT. + */ +static int +_base_check_for_trigger_pages_support(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi26DriverTriggerPage0_t trigger_pg0; + int r = 0; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + + r = mpt3sas_config_get_driver_trigger_pg0(ioc, &mpi_reply, + &trigger_pg0); + if (r) + return -EFAULT; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + return -EFAULT; + + return le16_to_cpu(trigger_pg0.TriggerFlags); +} + +/** + * _base_get_diag_triggers - Retrieve diag trigger values from + * persistent pages. + * @ioc : per adapter object + * + * Return nothing. + */ +static void +_base_get_diag_triggers(struct MPT3SAS_ADAPTER *ioc) +{ + u16 trigger_flags; + + /* + * Default setting of master trigger. + */ + ioc->diag_trigger_master.MasterData = + (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); + + trigger_flags = _base_check_for_trigger_pages_support(ioc); + if (trigger_flags < 0) + return; + + ioc->supports_trigger_pages = 1; + + /* + * Retrieve master diag trigger values from driver trigger pg1 + * if master trigger bit enabled in TriggerFlags. + */ + if ((u16)trigger_flags & + MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID) + _base_get_master_diag_triggers(ioc); + + /* + * Retrieve event diag trigger values from driver trigger pg2 + * if event trigger bit enabled in TriggerFlags. + */ + if ((u16)trigger_flags & + MPI26_DRIVER_TRIGGER0_FLAG_MPI_EVENT_TRIGGER_VALID) + _base_get_event_diag_triggers(ioc); + + /* + * Retrieve scsi diag trigger values from driver trigger pg3 + * if scsi trigger bit enabled in TriggerFlags. + */ + if ((u16)trigger_flags & + MPI26_DRIVER_TRIGGER0_FLAG_SCSI_SENSE_TRIGGER_VALID) + _base_get_scsi_diag_triggers(ioc); + /* + * Retrieve mpi error diag trigger values from driver trigger pg4 + * if loginfo trigger bit enabled in TriggerFlags. + */ + if ((u16)trigger_flags & + MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID) + _base_get_mpi_diag_triggers(ioc); +} + +/** + * _base_update_diag_trigger_pages - Update the driver trigger pages after + * online FW update, incase updated FW supports driver + * trigger pages. + * @ioc : per adapter object + * + * Return nothing. + */ +static void +_base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc) +{ + + if (ioc->diag_trigger_master.MasterData) + mpt3sas_config_update_driver_trigger_pg1(ioc, + &ioc->diag_trigger_master, 1); + + if (ioc->diag_trigger_event.ValidEntries) + mpt3sas_config_update_driver_trigger_pg2(ioc, + &ioc->diag_trigger_event, 1); + + if (ioc->diag_trigger_scsi.ValidEntries) + mpt3sas_config_update_driver_trigger_pg3(ioc, + &ioc->diag_trigger_scsi, 1); + + if (ioc->diag_trigger_mpi.ValidEntries) + mpt3sas_config_update_driver_trigger_pg4(ioc, + &ioc->diag_trigger_mpi, 1); +} + +/** * _base_static_config_pages - static start of day config pages * @ioc: per adapter object */ @@ -4729,7 +5118,7 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) { Mpi2ConfigReply_t mpi_reply; u32 iounit_pg1_flags; - + int tg_flags = 0; ioc->nvme_abort_timeout = 30; mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); if (ioc->ir_firmware) @@ -4761,7 +5150,24 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) else ioc->nvme_abort_timeout = ioc->manu_pg11.NVMeAbortTO; } - + ioc->time_sync_interval = + ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_MASK; + if (ioc->time_sync_interval) { + if (ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_UNIT_MASK) + ioc->time_sync_interval = + ioc->time_sync_interval * SECONDS_PER_HOUR; + else + ioc->time_sync_interval = + ioc->time_sync_interval * SECONDS_PER_MIN; + dinitprintk(ioc, ioc_info(ioc, + "Driver-FW TimeSync interval is %d seconds. ManuPg11 TimeSync Unit is in %s\n", + ioc->time_sync_interval, (ioc->manu_pg11.TimeSyncInterval & + MPT3SAS_TIMESYNC_UNIT_MASK) ? "Hour" : "Minute")); + } else { + if (ioc->is_gen35_ioc) + ioc_warn(ioc, + "TimeSync Interval in Manuf page-11 is not enabled. Periodic Time-Sync will be disabled\n"); + } mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); @@ -4789,6 +5195,29 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; if (ioc->is_aero_ioc) _base_update_ioc_page1_inlinewith_perf_mode(ioc); + if (ioc->is_gen35_ioc) { + if (ioc->is_driver_loading) + _base_get_diag_triggers(ioc); + else { + /* + * In case of online HBA FW update operation, + * check whether updated FW supports the driver trigger + * pages or not. + * - If previous FW has not supported driver trigger + * pages and newer FW supports them then update these + * pages with current diag trigger values. + * - If previous FW has supported driver trigger pages + * and new FW doesn't support them then disable + * support_trigger_pages flag. + */ + tg_flags = _base_check_for_trigger_pages_support(ioc); + if (!ioc->supports_trigger_pages && tg_flags != -EFAULT) + _base_update_diag_trigger_pages(ioc); + else if (ioc->supports_trigger_pages && + tg_flags == -EFAULT) + ioc->supports_trigger_pages = 0; + } + } } /** @@ -6473,6 +6902,8 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc) r = -EIO; } + /* Reset TimeSync Counter*/ + ioc->timestamp_update_count = 0; return r; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index bc8beb10f3fc..2def7a340616 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -71,13 +71,14 @@ #include "mpt3sas_debug.h" #include "mpt3sas_trigger_diag.h" +#include "mpt3sas_trigger_pages.h" /* driver versioning info */ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>" #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "35.100.00.00" -#define MPT3SAS_MAJOR_VERSION 35 +#define MPT3SAS_DRIVER_VERSION "36.100.00.00" +#define MPT3SAS_MAJOR_VERSION 36 #define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 @@ -93,6 +94,14 @@ /* CoreDump: Default timeout */ #define MPT3SAS_DEFAULT_COREDUMP_TIMEOUT_SECONDS (15) /*15 seconds*/ #define MPT3SAS_COREDUMP_LOOP_DONE (0xFF) +#define MPT3SAS_TIMESYNC_TIMEOUT_SECONDS (10) /* 10 seconds */ +#define MPT3SAS_TIMESYNC_UPDATE_INTERVAL (900) /* 15 minutes */ +#define MPT3SAS_TIMESYNC_UNIT_MASK (0x80) /* bit 7 */ +#define MPT3SAS_TIMESYNC_MASK (0x7F) /* 0 - 6 bits */ +#define SECONDS_PER_MIN (60) +#define SECONDS_PER_HOUR (3600) +#define MPT3SAS_COREDUMP_LOOP_DONE (0xFF) +#define MPI26_SET_IOC_PARAMETER_SYNC_TIMESTAMP (0x81) /* * Set MPT3SAS_SG_DEPTH value based on user input. @@ -405,7 +414,7 @@ struct Mpi2ManufacturingPage11_t { u16 HostTraceBufferMaxSizeKB; /* 50h */ u16 HostTraceBufferMinSizeKB; /* 52h */ u8 CoreDumpTOSec; /* 54h */ - u8 Reserved8; /* 55h */ + u8 TimeSyncInterval; /* 55h */ u16 Reserved9; /* 56h */ __le32 Reserved10; /* 58h */ }; @@ -420,6 +429,7 @@ struct Mpi2ManufacturingPage11_t { * @flags: MPT_TARGET_FLAGS_XXX flags * @deleted: target flaged for deletion * @tm_busy: target is busy with TM request. + * @port: hba port entry containing target's port number info * @sas_dev: The sas_device associated with this target * @pcie_dev: The pcie device associated with this target */ @@ -432,6 +442,7 @@ struct MPT3SAS_TARGET { u32 flags; u8 deleted; u8 tm_busy; + struct hba_port *port; struct _sas_device *sas_dev; struct _pcie_device *pcie_dev; }; @@ -534,6 +545,9 @@ struct _internal_cmd { * addition routine. * @chassis_slot: chassis slot * @is_chassis_slot_valid: chassis slot valid or not + * @port: hba port entry containing device's port number info + * @rphy: device's sas_rphy address used to identify this device structure in + * target_alloc callback function */ struct _sas_device { struct list_head list; @@ -560,6 +574,8 @@ struct _sas_device { u8 is_chassis_slot_valid; u8 connector_name[5]; struct kref refcount; + struct hba_port *port; + struct sas_rphy *rphy; }; static inline void sas_device_get(struct _sas_device *s) @@ -730,6 +746,7 @@ struct _boot_device { * @remote_identify: attached device identification * @rphy: sas transport rphy object * @port: sas transport wide/narrow port object + * @hba_port: hba port entry containing port's port number info * @phy_list: _sas_phy list objects belonging to this port */ struct _sas_port { @@ -738,6 +755,7 @@ struct _sas_port { struct sas_identify remote_identify; struct sas_rphy *rphy; struct sas_port *port; + struct hba_port *hba_port; struct list_head phy_list; }; @@ -751,6 +769,7 @@ struct _sas_port { * @handle: device handle for this phy * @attached_handle: device handle for attached device * @phy_belongs_to_port: port has been created for this phy + * @port: hba port entry containing port number info */ struct _sas_phy { struct list_head port_siblings; @@ -761,6 +780,8 @@ struct _sas_phy { u16 handle; u16 attached_handle; u8 phy_belongs_to_port; + u8 hba_vphy; + struct hba_port *port; }; /** @@ -776,6 +797,8 @@ struct _sas_phy { * @responding: used in _scsih_expander_device_mark_responding * @phy: a list of phys that make up this sas_host/expander * @sas_port_list: list of ports attached to this sas_host/expander + * @port: hba port entry containing node's port number info + * @rphy: sas_rphy object of this expander */ struct _sas_node { struct list_head list; @@ -787,11 +810,12 @@ struct _sas_node { u16 enclosure_handle; u64 enclosure_logical_id; u8 responding; + struct hba_port *port; struct _sas_phy *phy; struct list_head sas_port_list; + struct sas_rphy *rphy; }; - /** * struct _enclosure_node - enclosure information * @list: list of enclosures @@ -1009,6 +1033,46 @@ struct reply_post_struct { dma_addr_t reply_post_free_dma; }; +/** + * struct virtual_phy - vSES phy structure + * sas_address: SAS Address of vSES device + * phy_mask: vSES device's phy number + * flags: flags used to manage this structure + */ +struct virtual_phy { + struct list_head list; + u64 sas_address; + u32 phy_mask; + u8 flags; +}; + +#define MPT_VPHY_FLAG_DIRTY_PHY 0x01 + +/** + * struct hba_port - Saves each HBA's Wide/Narrow port info + * @sas_address: sas address of this wide/narrow port's attached device + * @phy_mask: HBA PHY's belonging to this port + * @port_id: port number + * @flags: hba port flags + * @vphys_mask : mask of vSES devices Phy number + * @vphys_list : list containing vSES device structures + */ +struct hba_port { + struct list_head list; + u64 sas_address; + u32 phy_mask; + u8 port_id; + u8 flags; + u32 vphys_mask; + struct list_head vphys_list; +}; + +/* hba port flags */ +#define HBA_PORT_FLAG_DIRTY_PORT 0x01 +#define HBA_PORT_FLAG_NEW_PORT 0x02 + +#define MULTIPATH_DISABLED_PORT_ID 0xFF + typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); /** * struct MPT3SAS_ADAPTER - per adapter struct @@ -1058,6 +1122,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @cpu_msix_table_sz: table size * @total_io_cnt: Gives total IO count, used to load balance the interrupts * @ioc_coredump_loop: will have non-zero value when FW is in CoreDump state + * @timestamp_update_count: Counter to fire timeSync command + * time_sync_interval: Time sync interval read from man page 11 * @high_iops_outstanding: used to load balance the interrupts * within high iops reply queues * @msix_load_balance: Enables load balancing of interrupts across @@ -1191,6 +1257,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * which ensures the syncrhonization between cli/sysfs_show path. * @atomic_desc_capable: Atomic Request Descriptor support. * @GET_MSIX_INDEX: Get the msix index of high iops queues. + * @multipath_on_hba: flag to determine multipath on hba is enabled or not + * @port_table_list: list containing HBA's wide/narrow port's info */ struct MPT3SAS_ADAPTER { struct list_head list; @@ -1251,6 +1319,8 @@ struct MPT3SAS_ADAPTER { MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; u32 non_operational_loop; u8 ioc_coredump_loop; + u32 timestamp_update_count; + u32 time_sync_interval; atomic64_t total_io_cnt; atomic64_t high_iops_outstanding; bool msix_load_balance; @@ -1472,6 +1542,7 @@ struct MPT3SAS_ADAPTER { struct SL_WH_EVENT_TRIGGERS_T diag_trigger_event; struct SL_WH_SCSI_TRIGGERS_T diag_trigger_scsi; struct SL_WH_MPI_TRIGGERS_T diag_trigger_mpi; + u8 supports_trigger_pages; void *device_remove_in_progress; u16 device_remove_in_progress_sz; u8 is_gen35_ioc; @@ -1483,6 +1554,9 @@ struct MPT3SAS_ADAPTER { PUT_SMID_IO_FP_HIP put_smid_hi_priority; PUT_SMID_DEFAULT put_smid_default; GET_MSIX_INDEX get_msix_index_for_smlio; + + u8 multipath_on_hba; + struct list_head port_table_list; }; struct mpt3sas_debugfs_buffer { @@ -1619,20 +1693,27 @@ int mpt3sas_scsih_issue_locked_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, void mpt3sas_scsih_set_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle); void mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle); -void mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address); +void mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, + struct hba_port *port); void mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, - u64 sas_address); + u64 sas_address, struct hba_port *port); u8 mpt3sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc, u16 smid); +struct hba_port * +mpt3sas_get_port_by_id(struct MPT3SAS_ADAPTER *ioc, u8 port, + u8 bypass_dirty_port_flag); struct _sas_node *mpt3sas_scsih_expander_find_by_handle( struct MPT3SAS_ADAPTER *ioc, u16 handle); struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address( - struct MPT3SAS_ADAPTER *ioc, u64 sas_address); + struct MPT3SAS_ADAPTER *ioc, u64 sas_address, + struct hba_port *port); struct _sas_device *mpt3sas_get_sdev_by_addr( - struct MPT3SAS_ADAPTER *ioc, u64 sas_address); + struct MPT3SAS_ADAPTER *ioc, u64 sas_address, + struct hba_port *port); struct _sas_device *__mpt3sas_get_sdev_by_addr( - struct MPT3SAS_ADAPTER *ioc, u64 sas_address); + struct MPT3SAS_ADAPTER *ioc, u64 sas_address, + struct hba_port *port); struct _sas_device *mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle); struct _pcie_device *mpt3sas_get_pdev_by_handle(struct MPT3SAS_ADAPTER *ioc, @@ -1642,6 +1723,11 @@ void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc); struct _raid_device * mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle); void mpt3sas_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth); +struct _sas_device * +__mpt3sas_get_sdev_by_rphy(struct MPT3SAS_ADAPTER *ioc, struct sas_rphy *rphy); +struct virtual_phy * +mpt3sas_get_vphy_by_phy(struct MPT3SAS_ADAPTER *ioc, + struct hba_port *port, u32 phy); /* config shared API */ u8 mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, @@ -1733,6 +1819,33 @@ int mpt3sas_config_get_volume_handle(struct MPT3SAS_ADAPTER *ioc, u16 pd_handle, u16 *volume_handle); int mpt3sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc, u16 volume_handle, u64 *wwid); +int +mpt3sas_config_get_driver_trigger_pg0(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage0_t *config_page); +int +mpt3sas_config_get_driver_trigger_pg1(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage1_t *config_page); +int +mpt3sas_config_get_driver_trigger_pg2(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage2_t *config_page); +int +mpt3sas_config_get_driver_trigger_pg3(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage3_t *config_page); +int +mpt3sas_config_get_driver_trigger_pg4(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage4_t *config_page); +int +mpt3sas_config_update_driver_trigger_pg1(struct MPT3SAS_ADAPTER *ioc, + struct SL_WH_MASTER_TRIGGER_T *master_tg, bool set); +int +mpt3sas_config_update_driver_trigger_pg2(struct MPT3SAS_ADAPTER *ioc, + struct SL_WH_EVENT_TRIGGERS_T *event_tg, bool set); +int +mpt3sas_config_update_driver_trigger_pg3(struct MPT3SAS_ADAPTER *ioc, + struct SL_WH_SCSI_TRIGGERS_T *scsi_tg, bool set); +int +mpt3sas_config_update_driver_trigger_pg4(struct MPT3SAS_ADAPTER *ioc, + struct SL_WH_MPI_TRIGGERS_T *mpi_tg, bool set); /* ctl shared API */ extern struct device_attribute *mpt3sas_host_attrs[]; @@ -1759,18 +1872,26 @@ extern struct scsi_transport_template *mpt3sas_transport_template; u8 mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); struct _sas_port *mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, - u16 handle, u64 sas_address); + u16 handle, u64 sas_address, struct hba_port *port); void mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, - u64 sas_address_parent); + u64 sas_address_parent, struct hba_port *port); int mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy *mpt3sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev); int mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy *mpt3sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev); void mpt3sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc, - u64 sas_address, u16 handle, u8 phy_number, u8 link_rate); + u64 sas_address, u16 handle, u8 phy_number, u8 link_rate, + struct hba_port *port); extern struct sas_function_template mpt3sas_transport_functions; extern struct scsi_transport_template *mpt3sas_transport_template; +void +mpt3sas_transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc, + struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy); +void +mpt3sas_transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc, + struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy, + u64 sas_address, struct hba_port *port); /* trigger data externs */ void mpt3sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc, struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data); diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index 4a0ddc7c95e4..8238843523b5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -1743,6 +1743,766 @@ mpt3sas_config_get_phys_disk_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t } /** + * mpt3sas_config_get_driver_trigger_pg0 - obtain driver trigger page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_driver_trigger_pg0(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage0_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE0_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_set_driver_trigger_pg0 - write driver trigger page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_config_set_driver_trigger_pg0(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage0_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE0_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_update_driver_trigger_pg0 - update driver trigger page 0 + * @ioc: per adapter object + * @trigger_flag: trigger type bit map + * @set: set ot clear trigger values + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +static int +mpt3sas_config_update_driver_trigger_pg0(struct MPT3SAS_ADAPTER *ioc, + u16 trigger_flag, bool set) +{ + Mpi26DriverTriggerPage0_t tg_pg0; + Mpi2ConfigReply_t mpi_reply; + int rc; + u16 flags, ioc_status; + + rc = mpt3sas_config_get_driver_trigger_pg0(ioc, &mpi_reply, &tg_pg0); + if (rc) + return rc; + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg0, ioc_status(0x%04x)\n", + __func__, ioc_status)); + return -EFAULT; + } + + if (set) + flags = le16_to_cpu(tg_pg0.TriggerFlags) | trigger_flag; + else + flags = le16_to_cpu(tg_pg0.TriggerFlags) & ~trigger_flag; + + tg_pg0.TriggerFlags = cpu_to_le16(flags); + + rc = _config_set_driver_trigger_pg0(ioc, &mpi_reply, &tg_pg0); + if (rc) + return rc; + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to update trigger pg0, ioc_status(0x%04x)\n", + __func__, ioc_status)); + return -EFAULT; + } + + return 0; +} + +/** + * mpt3sas_config_get_driver_trigger_pg1 - obtain driver trigger page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_driver_trigger_pg1(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage1_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE1_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_set_driver_trigger_pg1 - write driver trigger page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_config_set_driver_trigger_pg1(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage1_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE1_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_update_driver_trigger_pg1 - update driver trigger page 1 + * @ioc: per adapter object + * @master_tg: Master trigger bit map + * @set: set ot clear trigger values + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_update_driver_trigger_pg1(struct MPT3SAS_ADAPTER *ioc, + struct SL_WH_MASTER_TRIGGER_T *master_tg, bool set) +{ + Mpi26DriverTriggerPage1_t tg_pg1; + Mpi2ConfigReply_t mpi_reply; + int rc; + u16 ioc_status; + + rc = mpt3sas_config_update_driver_trigger_pg0(ioc, + MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID, set); + if (rc) + return rc; + + rc = mpt3sas_config_get_driver_trigger_pg1(ioc, &mpi_reply, &tg_pg1); + if (rc) + goto out; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg1, ioc_status(0x%04x)\n", + __func__, ioc_status)); + rc = -EFAULT; + goto out; + } + + if (set) { + tg_pg1.NumMasterTrigger = cpu_to_le16(1); + tg_pg1.MasterTriggers[0].MasterTriggerFlags = cpu_to_le32( + master_tg->MasterData); + } else { + tg_pg1.NumMasterTrigger = 0; + tg_pg1.MasterTriggers[0].MasterTriggerFlags = 0; + } + + rc = _config_set_driver_trigger_pg1(ioc, &mpi_reply, &tg_pg1); + if (rc) + goto out; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg1, ioc_status(0x%04x)\n", + __func__, ioc_status)); + rc = -EFAULT; + goto out; + } + + return 0; + +out: + mpt3sas_config_update_driver_trigger_pg0(ioc, + MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID, !set); + + return rc; +} + +/** + * mpt3sas_config_get_driver_trigger_pg2 - obtain driver trigger page 2 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_driver_trigger_pg2(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage2_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 2; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE2_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_set_driver_trigger_pg2 - write driver trigger page 2 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_config_set_driver_trigger_pg2(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage2_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 2; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE2_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_update_driver_trigger_pg2 - update driver trigger page 2 + * @ioc: per adapter object + * @event_tg: list of Event Triggers + * @set: set ot clear trigger values + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_update_driver_trigger_pg2(struct MPT3SAS_ADAPTER *ioc, + struct SL_WH_EVENT_TRIGGERS_T *event_tg, bool set) +{ + Mpi26DriverTriggerPage2_t tg_pg2; + Mpi2ConfigReply_t mpi_reply; + int rc, i, count; + u16 ioc_status; + + rc = mpt3sas_config_update_driver_trigger_pg0(ioc, + MPI26_DRIVER_TRIGGER0_FLAG_MPI_EVENT_TRIGGER_VALID, set); + if (rc) + return rc; + + rc = mpt3sas_config_get_driver_trigger_pg2(ioc, &mpi_reply, &tg_pg2); + if (rc) + goto out; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg2, ioc_status(0x%04x)\n", + __func__, ioc_status)); + rc = -EFAULT; + goto out; + } + + if (set) { + count = event_tg->ValidEntries; + tg_pg2.NumMPIEventTrigger = cpu_to_le16(count); + for (i = 0; i < count; i++) { + tg_pg2.MPIEventTriggers[i].MPIEventCode = + cpu_to_le16( + event_tg->EventTriggerEntry[i].EventValue); + tg_pg2.MPIEventTriggers[i].MPIEventCodeSpecific = + cpu_to_le16( + event_tg->EventTriggerEntry[i].LogEntryQualifier); + } + } else { + tg_pg2.NumMPIEventTrigger = 0; + memset(&tg_pg2.MPIEventTriggers[0], 0, + NUM_VALID_ENTRIES * sizeof( + MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY)); + } + + rc = _config_set_driver_trigger_pg2(ioc, &mpi_reply, &tg_pg2); + if (rc) + goto out; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg2, ioc_status(0x%04x)\n", + __func__, ioc_status)); + rc = -EFAULT; + goto out; + } + + return 0; + +out: + mpt3sas_config_update_driver_trigger_pg0(ioc, + MPI26_DRIVER_TRIGGER0_FLAG_MPI_EVENT_TRIGGER_VALID, !set); + + return rc; +} + +/** + * mpt3sas_config_get_driver_trigger_pg3 - obtain driver trigger page 3 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_driver_trigger_pg3(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage3_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 3; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE3_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_set_driver_trigger_pg3 - write driver trigger page 3 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_config_set_driver_trigger_pg3(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage3_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 3; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE3_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_update_driver_trigger_pg3 - update driver trigger page 3 + * @ioc: per adapter object + * @scsi_tg: scsi trigger list + * @set: set ot clear trigger values + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_update_driver_trigger_pg3(struct MPT3SAS_ADAPTER *ioc, + struct SL_WH_SCSI_TRIGGERS_T *scsi_tg, bool set) +{ + Mpi26DriverTriggerPage3_t tg_pg3; + Mpi2ConfigReply_t mpi_reply; + int rc, i, count; + u16 ioc_status; + + rc = mpt3sas_config_update_driver_trigger_pg0(ioc, + MPI26_DRIVER_TRIGGER0_FLAG_SCSI_SENSE_TRIGGER_VALID, set); + if (rc) + return rc; + + rc = mpt3sas_config_get_driver_trigger_pg3(ioc, &mpi_reply, &tg_pg3); + if (rc) + goto out; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg3, ioc_status(0x%04x)\n", + __func__, ioc_status)); + return -EFAULT; + } + + if (set) { + count = scsi_tg->ValidEntries; + tg_pg3.NumSCSISenseTrigger = cpu_to_le16(count); + for (i = 0; i < count; i++) { + tg_pg3.SCSISenseTriggers[i].ASCQ = + scsi_tg->SCSITriggerEntry[i].ASCQ; + tg_pg3.SCSISenseTriggers[i].ASC = + scsi_tg->SCSITriggerEntry[i].ASC; + tg_pg3.SCSISenseTriggers[i].SenseKey = + scsi_tg->SCSITriggerEntry[i].SenseKey; + } + } else { + tg_pg3.NumSCSISenseTrigger = 0; + memset(&tg_pg3.SCSISenseTriggers[0], 0, + NUM_VALID_ENTRIES * sizeof( + MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY)); + } + + rc = _config_set_driver_trigger_pg3(ioc, &mpi_reply, &tg_pg3); + if (rc) + goto out; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg3, ioc_status(0x%04x)\n", + __func__, ioc_status)); + return -EFAULT; + } + + return 0; +out: + mpt3sas_config_update_driver_trigger_pg0(ioc, + MPI26_DRIVER_TRIGGER0_FLAG_SCSI_SENSE_TRIGGER_VALID, !set); + + return rc; +} + +/** + * mpt3sas_config_get_driver_trigger_pg4 - obtain driver trigger page 4 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_driver_trigger_pg4(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage4_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 4; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE4_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_set_driver_trigger_pg4 - write driver trigger page 4 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_config_set_driver_trigger_pg4(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi26DriverTriggerPage4_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = + MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER; + mpi_request.Header.PageNumber = 4; + mpi_request.Header.PageVersion = MPI26_DRIVER_TRIGGER_PAGE4_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_update_driver_trigger_pg4 - update driver trigger page 4 + * @ioc: per adapter object + * @mpi_tg: mpi trigger list + * @set: set ot clear trigger values + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_update_driver_trigger_pg4(struct MPT3SAS_ADAPTER *ioc, + struct SL_WH_MPI_TRIGGERS_T *mpi_tg, bool set) +{ + Mpi26DriverTriggerPage4_t tg_pg4; + Mpi2ConfigReply_t mpi_reply; + int rc, i, count; + u16 ioc_status; + + rc = mpt3sas_config_update_driver_trigger_pg0(ioc, + MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID, set); + if (rc) + return rc; + + rc = mpt3sas_config_get_driver_trigger_pg4(ioc, &mpi_reply, &tg_pg4); + if (rc) + goto out; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg4, ioc_status(0x%04x)\n", + __func__, ioc_status)); + rc = -EFAULT; + goto out; + } + + if (set) { + count = mpi_tg->ValidEntries; + tg_pg4.NumIOCStatusLogInfoTrigger = cpu_to_le16(count); + for (i = 0; i < count; i++) { + tg_pg4.IOCStatusLoginfoTriggers[i].IOCStatus = + cpu_to_le16(mpi_tg->MPITriggerEntry[i].IOCStatus); + tg_pg4.IOCStatusLoginfoTriggers[i].LogInfo = + cpu_to_le32(mpi_tg->MPITriggerEntry[i].IocLogInfo); + } + } else { + tg_pg4.NumIOCStatusLogInfoTrigger = 0; + memset(&tg_pg4.IOCStatusLoginfoTriggers[0], 0, + NUM_VALID_ENTRIES * sizeof( + MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY)); + } + + rc = _config_set_driver_trigger_pg4(ioc, &mpi_reply, &tg_pg4); + if (rc) + goto out; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + dcprintk(ioc, + ioc_err(ioc, + "%s: Failed to get trigger pg4, ioc_status(0x%04x)\n", + __func__, ioc_status)); + rc = -EFAULT; + goto out; + } + + return 0; + +out: + mpt3sas_config_update_driver_trigger_pg0(ioc, + MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID, !set); + + return rc; +} + +/** * mpt3sas_config_get_volume_handle - returns volume handle for give hidden * raid components * @ioc: per adapter object diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index edd26a2570fa..c8a0ce18f2c5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -902,8 +902,10 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, (Mpi2SmpPassthroughRequest_t *)mpi_request; u8 *data; - /* ioc determines which port to use */ - smp_request->PhysicalPort = 0xFF; + if (!ioc->multipath_on_hba) { + /* ioc determines which port to use */ + smp_request->PhysicalPort = 0xFF; + } if (smp_request->PassthroughFlags & MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE) data = (u8 *)&smp_request->SGL; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 5f845d7094fc..c8b09a81834d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -159,6 +159,15 @@ module_param(enable_sdev_max_qd, bool, 0444); MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue, def=disabled(0)"); +static int multipath_on_hba = -1; +module_param(multipath_on_hba, int, 0); +MODULE_PARM_DESC(multipath_on_hba, + "Multipath support to add same target device\n\t\t" + "as many times as it is visible to HBA from various paths\n\t\t" + "(by default:\n\t\t" + "\t SAS 2.0 & SAS 3.0 HBA - This will be disabled,\n\t\t" + "\t SAS 3.5 HBA - This will be enabled)"); + /* raid transport support */ static struct raid_template *mpt3sas_raid_template; static struct raid_template *mpt2sas_raid_template; @@ -357,6 +366,87 @@ _scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number, } /** + * mpt3sas_get_port_by_id - get hba port entry corresponding to provided + * port number from port list + * @ioc: per adapter object + * @port_id: port number + * @bypass_dirty_port_flag: when set look the matching hba port entry even + * if hba port entry is marked as dirty. + * + * Search for hba port entry corresponding to provided port number, + * if available return port object otherwise return NULL. + */ +struct hba_port * +mpt3sas_get_port_by_id(struct MPT3SAS_ADAPTER *ioc, + u8 port_id, u8 bypass_dirty_port_flag) +{ + struct hba_port *port, *port_next; + + /* + * When multipath_on_hba is disabled then + * search the hba_port entry using default + * port id i.e. 255 + */ + if (!ioc->multipath_on_hba) + port_id = MULTIPATH_DISABLED_PORT_ID; + + list_for_each_entry_safe(port, port_next, + &ioc->port_table_list, list) { + if (port->port_id != port_id) + continue; + if (bypass_dirty_port_flag) + return port; + if (port->flags & HBA_PORT_FLAG_DIRTY_PORT) + continue; + return port; + } + + /* + * Allocate hba_port object for default port id (i.e. 255) + * when multipath_on_hba is disabled for the HBA. + * And add this object to port_table_list. + */ + if (!ioc->multipath_on_hba) { + port = kzalloc(sizeof(struct hba_port), GFP_KERNEL); + if (!port) + return NULL; + + port->port_id = port_id; + ioc_info(ioc, + "hba_port entry: %p, port: %d is added to hba_port list\n", + port, port->port_id); + list_add_tail(&port->list, + &ioc->port_table_list); + return port; + } + return NULL; +} + +/** + * mpt3sas_get_vphy_by_phy - get virtual_phy object corresponding to phy number + * @ioc: per adapter object + * @port: hba_port object + * @phy: phy number + * + * Return virtual_phy object corresponding to phy number. + */ +struct virtual_phy * +mpt3sas_get_vphy_by_phy(struct MPT3SAS_ADAPTER *ioc, + struct hba_port *port, u32 phy) +{ + struct virtual_phy *vphy, *vphy_next; + + if (!port->vphys_mask) + return NULL; + + list_for_each_entry_safe(vphy, vphy_next, &port->vphys_list, list) { + if (vphy->phy_mask & (1 << phy)) + return vphy; + } + return NULL; +} + +/** * _scsih_is_boot_device - search for matching boot device. * @sas_address: sas address * @device_name: device name specified in INDENTIFY fram @@ -614,48 +704,105 @@ mpt3sas_get_pdev_from_target(struct MPT3SAS_ADAPTER *ioc, return ret; } + +/** + * __mpt3sas_get_sdev_by_rphy - sas device search + * @ioc: per adapter object + * @rphy: sas_rphy pointer + * + * Context: This function will acquire ioc->sas_device_lock and will release + * before returning the sas_device object. + * + * This searches for sas_device from rphy object + * then return sas_device object. + */ struct _sas_device * -__mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, - u64 sas_address) +__mpt3sas_get_sdev_by_rphy(struct MPT3SAS_ADAPTER *ioc, + struct sas_rphy *rphy) { struct _sas_device *sas_device; assert_spin_locked(&ioc->sas_device_lock); - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->sas_address == sas_address) - goto found_device; + list_for_each_entry(sas_device, &ioc->sas_device_list, list) { + if (sas_device->rphy != rphy) + continue; + sas_device_get(sas_device); + return sas_device; + } - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->sas_address == sas_address) - goto found_device; + sas_device = NULL; + list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) { + if (sas_device->rphy != rphy) + continue; + sas_device_get(sas_device); + return sas_device; + } return NULL; +} -found_device: - sas_device_get(sas_device); - return sas_device; +/** + * mpt3sas_get_sdev_by_addr - get _sas_device object corresponding to provided + * sas address from sas_device_list list + * @ioc: per adapter object + * @port: port number + * + * Search for _sas_device object corresponding to provided sas address, + * if available return _sas_device object address otherwise return NULL. + */ +struct _sas_device * +__mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, + u64 sas_address, struct hba_port *port) +{ + struct _sas_device *sas_device; + + if (!port) + return NULL; + + assert_spin_locked(&ioc->sas_device_lock); + + list_for_each_entry(sas_device, &ioc->sas_device_list, list) { + if (sas_device->sas_address != sas_address) + continue; + if (sas_device->port != port) + continue; + sas_device_get(sas_device); + return sas_device; + } + + list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) { + if (sas_device->sas_address != sas_address) + continue; + if (sas_device->port != port) + continue; + sas_device_get(sas_device); + return sas_device; + } + + return NULL; } /** * mpt3sas_get_sdev_by_addr - sas device search * @ioc: per adapter object * @sas_address: sas address + * @port: hba port entry * Context: Calling function should acquire ioc->sas_device_lock * - * This searches for sas_device based on sas_address, then return sas_device - * object. + * This searches for sas_device based on sas_address & port number, + * then return sas_device object. */ struct _sas_device * mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, - u64 sas_address) + u64 sas_address, struct hba_port *port) { struct _sas_device *sas_device; unsigned long flags; spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = __mpt3sas_get_sdev_by_addr(ioc, - sas_address); + sas_address, port); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return sas_device; @@ -824,13 +971,17 @@ _scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) } /** - * mpt3sas_device_remove_by_sas_address - removing device object by sas address + * mpt3sas_device_remove_by_sas_address - removing device object by + * sas address & port number * @ioc: per adapter object * @sas_address: device sas_address + * @port: hba port entry + * + * Return nothing. */ void mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, - u64 sas_address) + u64 sas_address, struct hba_port *port) { struct _sas_device *sas_device; unsigned long flags; @@ -839,7 +990,7 @@ mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address); + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address, port); if (sas_device) { list_del_init(&sas_device->list); sas_device_put(sas_device); @@ -884,7 +1035,7 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, } if (!mpt3sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { + sas_device->sas_address_parent, sas_device->port)) { _scsih_sas_device_remove(ioc, sas_device); } else if (!sas_device->starget) { /* @@ -895,7 +1046,8 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, if (!ioc->is_driver_loading) { mpt3sas_transport_port_remove(ioc, sas_device->sas_address, - sas_device->sas_address_parent); + sas_device->sas_address_parent, + sas_device->port); _scsih_sas_device_remove(ioc, sas_device); } } else @@ -1432,21 +1584,26 @@ out: * mpt3sas_scsih_expander_find_by_sas_address - expander device search * @ioc: per adapter object * @sas_address: sas address + * @port: hba port entry * Context: Calling function should acquire ioc->sas_node_lock. * - * This searches for expander device based on sas_address, then returns the - * sas_node object. + * This searches for expander device based on sas_address & port number, + * then returns the sas_node object. */ struct _sas_node * mpt3sas_scsih_expander_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, - u64 sas_address) + u64 sas_address, struct hba_port *port) { - struct _sas_node *sas_expander, *r; + struct _sas_node *sas_expander, *r = NULL; + + if (!port) + return r; - r = NULL; list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { if (sas_expander->sas_address != sas_address) continue; + if (sas_expander->port != port) + continue; r = sas_expander; goto out; } @@ -1744,6 +1901,7 @@ scsih_target_alloc(struct scsi_target *starget) if (pcie_device) { sas_target_priv_data->handle = pcie_device->handle; sas_target_priv_data->sas_address = pcie_device->wwid; + sas_target_priv_data->port = NULL; sas_target_priv_data->pcie_dev = pcie_device; pcie_device->starget = starget; pcie_device->id = starget->id; @@ -1761,12 +1919,12 @@ scsih_target_alloc(struct scsi_target *starget) /* sas/sata devices */ spin_lock_irqsave(&ioc->sas_device_lock, flags); rphy = dev_to_rphy(starget->dev.parent); - sas_device = __mpt3sas_get_sdev_by_addr(ioc, - rphy->identify.sas_address); + sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy); if (sas_device) { sas_target_priv_data->handle = sas_device->handle; sas_target_priv_data->sas_address = sas_device->sas_address; + sas_target_priv_data->port = sas_device->port; sas_target_priv_data->sas_dev = sas_device; sas_device->starget = starget; sas_device->id = starget->id; @@ -1922,7 +2080,8 @@ scsih_slave_alloc(struct scsi_device *sdev) } else if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = __mpt3sas_get_sdev_by_addr(ioc, - sas_target_priv_data->sas_address); + sas_target_priv_data->sas_address, + sas_target_priv_data->port); if (sas_device && (sas_device->starget == NULL)) { sdev_printk(KERN_INFO, sdev, "%s : sas_device->starget set to starget @ %d\n", @@ -2527,7 +2686,8 @@ scsih_slave_configure(struct scsi_device *sdev) spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = __mpt3sas_get_sdev_by_addr(ioc, - sas_device_priv_data->sas_target->sas_address); + sas_device_priv_data->sas_target->sas_address, + sas_device_priv_data->sas_target->port); if (!sas_device) { spin_unlock_irqrestore(&ioc->sas_device_lock, flags); dfailprintk(ioc, @@ -2762,8 +2922,8 @@ mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) /** * scsih_tm_cmd_map_status - map the target reset & LUN reset TM status - * @ioc - per adapter object - * @channel - the channel assigned by the OS + * @ioc: per adapter object + * @channel: the channel assigned by the OS * @id: the id assigned by the OS * @lun: lun number * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) @@ -2808,9 +2968,9 @@ scsih_tm_cmd_map_status(struct MPT3SAS_ADAPTER *ioc, uint channel, /** * scsih_tm_post_processing - post processing of target & LUN reset - * @ioc - per adapter object + * @ioc: per adapter object * @handle: device handle - * @channel - the channel assigned by the OS + * @channel: the channel assigned by the OS * @id: the id assigned by the OS * @lun: lun number * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) @@ -3513,6 +3673,8 @@ static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc) * * Walk the firmware event queue, either killing timers, or waiting * for outstanding events to complete + * + * Context: task, can sleep */ static void _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc) @@ -3520,7 +3682,7 @@ _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc) struct fw_event_work *fw_event; if ((list_empty(&ioc->fw_event_list) && !ioc->current_event) || - !ioc->firmware_event_thread || in_interrupt()) + !ioc->firmware_event_thread) return; ioc->fw_events_cleanup = 1; @@ -3642,11 +3804,13 @@ _scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc) * _scsih_ublock_io_device - prepare device to be deleted * @ioc: per adapter object * @sas_address: sas address + * @port: hba port entry * * unblock then put device in offline state */ static void -_scsih_ublock_io_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) +_scsih_ublock_io_device(struct MPT3SAS_ADAPTER *ioc, + u64 sas_address, struct hba_port *port) { struct MPT3SAS_DEVICE *sas_device_priv_data; struct scsi_device *sdev; @@ -3658,6 +3822,8 @@ _scsih_ublock_io_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) if (sas_device_priv_data->sas_target->sas_address != sas_address) continue; + if (sas_device_priv_data->sas_target->port != port) + continue; if (sas_device_priv_data->block) _scsih_internal_device_unblock(sdev, sas_device_priv_data); @@ -3758,7 +3924,8 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc, SAS_END_DEVICE) { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = __mpt3sas_get_sdev_by_addr(ioc, - mpt3sas_port->remote_identify.sas_address); + mpt3sas_port->remote_identify.sas_address, + mpt3sas_port->hba_port); if (sas_device) { set_bit(sas_device->handle, ioc->blocking_handles); @@ -3777,7 +3944,8 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc, SAS_FANOUT_EXPANDER_DEVICE) { expander_sibling = mpt3sas_scsih_expander_find_by_sas_address( - ioc, mpt3sas_port->remote_identify.sas_address); + ioc, mpt3sas_port->remote_identify.sas_address, + mpt3sas_port->hba_port); _scsih_block_io_to_children_attached_to_ex(ioc, expander_sibling); } @@ -3866,6 +4034,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) struct _tr_list *delayed_tr; u32 ioc_state; u8 tr_method = 0; + struct hba_port *port = NULL; if (ioc->pci_error_recovery) { dewtprintk(ioc, @@ -3894,6 +4063,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) sas_target_priv_data = sas_device->starget->hostdata; sas_target_priv_data->deleted = 1; sas_address = sas_device->sas_address; + port = sas_device->port; } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!sas_device) { @@ -3941,7 +4111,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) pcie_device->enclosure_level, pcie_device->connector_name)); } - _scsih_ublock_io_device(ioc, sas_address); + _scsih_ublock_io_device(ioc, sas_address, port); sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; } @@ -5715,6 +5885,614 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } /** + * _scsih_update_vphys_after_reset - update the Port's + * vphys_list after reset + * @ioc: per adapter object + * + * Returns nothing. + */ +static void +_scsih_update_vphys_after_reset(struct MPT3SAS_ADAPTER *ioc) +{ + u16 sz, ioc_status; + int i; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; + u16 attached_handle; + u64 attached_sas_addr; + u8 found = 0, port_id; + Mpi2SasPhyPage0_t phy_pg0; + struct hba_port *port, *port_next, *mport; + struct virtual_phy *vphy, *vphy_next; + struct _sas_device *sas_device; + + /* + * Mark all the vphys objects as dirty. + */ + list_for_each_entry_safe(port, port_next, + &ioc->port_table_list, list) { + if (!port->vphys_mask) + continue; + list_for_each_entry_safe(vphy, vphy_next, + &port->vphys_list, list) { + vphy->flags |= MPT_VPHY_FLAG_DIRTY_PHY; + } + } + + /* + * Read SASIOUnitPage0 to get each HBA Phy's data. + */ + sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + + (ioc->sas_hba.num_phys * sizeof(Mpi2SasIOUnit0PhyData_t)); + sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg0) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return; + } + if ((mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, + sas_iounit_pg0, sz)) != 0) + goto out; + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + goto out; + /* + * Loop over each HBA Phy. + */ + for (i = 0; i < ioc->sas_hba.num_phys; i++) { + /* + * Check whether Phy's Negotiation Link Rate is > 1.5G or not. + */ + if ((sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4) < + MPI2_SAS_NEG_LINK_RATE_1_5) + continue; + /* + * Check whether Phy is connected to SEP device or not, + * if it is SEP device then read the Phy's SASPHYPage0 data to + * determine whether Phy is a virtual Phy or not. if it is + * virtual phy then it is conformed that the attached remote + * device is a HBA's vSES device. + */ + if (!(le32_to_cpu( + sas_iounit_pg0->PhyData[i].ControllerPhyDeviceInfo) & + MPI2_SAS_DEVICE_INFO_SEP)) + continue; + + if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, + i))) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + continue; + } + + if (!(le32_to_cpu(phy_pg0.PhyInfo) & + MPI2_SAS_PHYINFO_VIRTUAL_PHY)) + continue; + /* + * Get the vSES device's SAS Address. + */ + attached_handle = le16_to_cpu( + sas_iounit_pg0->PhyData[i].AttachedDevHandle); + if (_scsih_get_sas_address(ioc, attached_handle, + &attached_sas_addr) != 0) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + continue; + } + + found = 0; + port = port_next = NULL; + /* + * Loop over each virtual_phy object from + * each port's vphys_list. + */ + list_for_each_entry_safe(port, + port_next, &ioc->port_table_list, list) { + if (!port->vphys_mask) + continue; + list_for_each_entry_safe(vphy, vphy_next, + &port->vphys_list, list) { + /* + * Continue with next virtual_phy object + * if the object is not marked as dirty. + */ + if (!(vphy->flags & MPT_VPHY_FLAG_DIRTY_PHY)) + continue; + + /* + * Continue with next virtual_phy object + * if the object's SAS Address is not equals + * to current Phy's vSES device SAS Address. + */ + if (vphy->sas_address != attached_sas_addr) + continue; + /* + * Enable current Phy number bit in object's + * phy_mask field. + */ + if (!(vphy->phy_mask & (1 << i))) + vphy->phy_mask = (1 << i); + /* + * Get hba_port object from hba_port table + * corresponding to current phy's Port ID. + * if there is no hba_port object corresponding + * to Phy's Port ID then create a new hba_port + * object & add to hba_port table. + */ + port_id = sas_iounit_pg0->PhyData[i].Port; + mport = mpt3sas_get_port_by_id(ioc, port_id, 1); + if (!mport) { + mport = kzalloc( + sizeof(struct hba_port), GFP_KERNEL); + if (!mport) + break; + mport->port_id = port_id; + ioc_info(ioc, + "%s: hba_port entry: %p, port: %d is added to hba_port list\n", + __func__, mport, mport->port_id); + list_add_tail(&mport->list, + &ioc->port_table_list); + } + /* + * If mport & port pointers are not pointing to + * same hba_port object then it means that vSES + * device's Port ID got changed after reset and + * hence move current virtual_phy object from + * port's vphys_list to mport's vphys_list. + */ + if (port != mport) { + if (!mport->vphys_mask) + INIT_LIST_HEAD( + &mport->vphys_list); + mport->vphys_mask |= (1 << i); + port->vphys_mask &= ~(1 << i); + list_move(&vphy->list, + &mport->vphys_list); + sas_device = mpt3sas_get_sdev_by_addr( + ioc, attached_sas_addr, port); + if (sas_device) + sas_device->port = mport; + } + /* + * Earlier while updating the hba_port table, + * it is determined that there is no other + * direct attached device with mport's Port ID, + * Hence mport was marked as dirty. Only vSES + * device has this Port ID, so unmark the mport + * as dirt. + */ + if (mport->flags & HBA_PORT_FLAG_DIRTY_PORT) { + mport->sas_address = 0; + mport->phy_mask = 0; + mport->flags &= + ~HBA_PORT_FLAG_DIRTY_PORT; + } + /* + * Unmark current virtual_phy object as dirty. + */ + vphy->flags &= ~MPT_VPHY_FLAG_DIRTY_PHY; + found = 1; + break; + } + if (found) + break; + } + } +out: + kfree(sas_iounit_pg0); +} + +/** + * _scsih_get_port_table_after_reset - Construct temporary port table + * @ioc: per adapter object + * @port_table: address where port table needs to be constructed + * + * return number of HBA port entries available after reset. + */ +static int +_scsih_get_port_table_after_reset(struct MPT3SAS_ADAPTER *ioc, + struct hba_port *port_table) +{ + u16 sz, ioc_status; + int i, j; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; + u16 attached_handle; + u64 attached_sas_addr; + u8 found = 0, port_count = 0, port_id; + + sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys + * sizeof(Mpi2SasIOUnit0PhyData_t)); + sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg0) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return port_count; + } + + if ((mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, + sas_iounit_pg0, sz)) != 0) + goto out; + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + goto out; + for (i = 0; i < ioc->sas_hba.num_phys; i++) { + found = 0; + if ((sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4) < + MPI2_SAS_NEG_LINK_RATE_1_5) + continue; + attached_handle = + le16_to_cpu(sas_iounit_pg0->PhyData[i].AttachedDevHandle); + if (_scsih_get_sas_address( + ioc, attached_handle, &attached_sas_addr) != 0) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + continue; + } + + for (j = 0; j < port_count; j++) { + port_id = sas_iounit_pg0->PhyData[i].Port; + if (port_table[j].port_id == port_id && + port_table[j].sas_address == attached_sas_addr) { + port_table[j].phy_mask |= (1 << i); + found = 1; + break; + } + } + + if (found) + continue; + + port_id = sas_iounit_pg0->PhyData[i].Port; + port_table[port_count].port_id = port_id; + port_table[port_count].phy_mask = (1 << i); + port_table[port_count].sas_address = attached_sas_addr; + port_count++; + } +out: + kfree(sas_iounit_pg0); + return port_count; +} + +enum hba_port_matched_codes { + NOT_MATCHED = 0, + MATCHED_WITH_ADDR_AND_PHYMASK, + MATCHED_WITH_ADDR_SUBPHYMASK_AND_PORT, + MATCHED_WITH_ADDR_AND_SUBPHYMASK, + MATCHED_WITH_ADDR, +}; + +/** + * _scsih_look_and_get_matched_port_entry - Get matched hba port entry + * from HBA port table + * @ioc: per adapter object + * @port_entry - hba port entry from temporary port table which needs to be + * searched for matched entry in the HBA port table + * @matched_port_entry - save matched hba port entry here + * @count - count of matched entries + * + * return type of matched entry found. + */ +static enum hba_port_matched_codes +_scsih_look_and_get_matched_port_entry(struct MPT3SAS_ADAPTER *ioc, + struct hba_port *port_entry, + struct hba_port **matched_port_entry, int *count) +{ + struct hba_port *port_table_entry, *matched_port = NULL; + enum hba_port_matched_codes matched_code = NOT_MATCHED; + int lcount = 0; + *matched_port_entry = NULL; + + list_for_each_entry(port_table_entry, &ioc->port_table_list, list) { + if (!(port_table_entry->flags & HBA_PORT_FLAG_DIRTY_PORT)) + continue; + + if ((port_table_entry->sas_address == port_entry->sas_address) + && (port_table_entry->phy_mask == port_entry->phy_mask)) { + matched_code = MATCHED_WITH_ADDR_AND_PHYMASK; + matched_port = port_table_entry; + break; + } + + if ((port_table_entry->sas_address == port_entry->sas_address) + && (port_table_entry->phy_mask & port_entry->phy_mask) + && (port_table_entry->port_id == port_entry->port_id)) { + matched_code = MATCHED_WITH_ADDR_SUBPHYMASK_AND_PORT; + matched_port = port_table_entry; + continue; + } + + if ((port_table_entry->sas_address == port_entry->sas_address) + && (port_table_entry->phy_mask & port_entry->phy_mask)) { + if (matched_code == + MATCHED_WITH_ADDR_SUBPHYMASK_AND_PORT) + continue; + matched_code = MATCHED_WITH_ADDR_AND_SUBPHYMASK; + matched_port = port_table_entry; + continue; + } + + if (port_table_entry->sas_address == port_entry->sas_address) { + if (matched_code == + MATCHED_WITH_ADDR_SUBPHYMASK_AND_PORT) + continue; + if (matched_code == MATCHED_WITH_ADDR_AND_SUBPHYMASK) + continue; + matched_code = MATCHED_WITH_ADDR; + matched_port = port_table_entry; + lcount++; + } + } + + *matched_port_entry = matched_port; + if (matched_code == MATCHED_WITH_ADDR) + *count = lcount; + return matched_code; +} + +/** + * _scsih_del_phy_part_of_anther_port - remove phy if it + * is a part of anther port + *@ioc: per adapter object + *@port_table: port table after reset + *@index: hba port entry index + *@port_count: number of ports available after host reset + *@offset: HBA phy bit offset + * + */ +static void +_scsih_del_phy_part_of_anther_port(struct MPT3SAS_ADAPTER *ioc, + struct hba_port *port_table, + int index, u8 port_count, int offset) +{ + struct _sas_node *sas_node = &ioc->sas_hba; + u32 i, found = 0; + + for (i = 0; i < port_count; i++) { + if (i == index) + continue; + + if (port_table[i].phy_mask & (1 << offset)) { + mpt3sas_transport_del_phy_from_an_existing_port( + ioc, sas_node, &sas_node->phy[offset]); + found = 1; + break; + } + } + if (!found) + port_table[index].phy_mask |= (1 << offset); +} + +/** + * _scsih_add_or_del_phys_from_existing_port - add/remove phy to/from + * right port + *@ioc: per adapter object + *@hba_port_entry: hba port table entry + *@port_table: temporary port table + *@index: hba port entry index + *@port_count: number of ports available after host reset + * + */ +static void +_scsih_add_or_del_phys_from_existing_port(struct MPT3SAS_ADAPTER *ioc, + struct hba_port *hba_port_entry, struct hba_port *port_table, + int index, int port_count) +{ + u32 phy_mask, offset = 0; + struct _sas_node *sas_node = &ioc->sas_hba; + + phy_mask = hba_port_entry->phy_mask ^ port_table[index].phy_mask; + + for (offset = 0; offset < ioc->sas_hba.num_phys; offset++) { + if (phy_mask & (1 << offset)) { + if (!(port_table[index].phy_mask & (1 << offset))) { + _scsih_del_phy_part_of_anther_port( + ioc, port_table, index, port_count, + offset); + continue; + } + if (sas_node->phy[offset].phy_belongs_to_port) + mpt3sas_transport_del_phy_from_an_existing_port( + ioc, sas_node, &sas_node->phy[offset]); + mpt3sas_transport_add_phy_to_an_existing_port( + ioc, sas_node, &sas_node->phy[offset], + hba_port_entry->sas_address, + hba_port_entry); + } + } +} + +/** + * _scsih_del_dirty_vphy - delete virtual_phy objects marked as dirty. + * @ioc: per adapter object + * + * Returns nothing. + */ +static void +_scsih_del_dirty_vphy(struct MPT3SAS_ADAPTER *ioc) +{ + struct hba_port *port, *port_next; + struct virtual_phy *vphy, *vphy_next; + + list_for_each_entry_safe(port, port_next, + &ioc->port_table_list, list) { + if (!port->vphys_mask) + continue; + list_for_each_entry_safe(vphy, vphy_next, + &port->vphys_list, list) { + if (vphy->flags & MPT_VPHY_FLAG_DIRTY_PHY) { + drsprintk(ioc, ioc_info(ioc, + "Deleting vphy %p entry from port id: %d\t, Phy_mask 0x%08x\n", + vphy, port->port_id, + vphy->phy_mask)); + port->vphys_mask &= ~vphy->phy_mask; + list_del(&vphy->list); + kfree(vphy); + } + } + if (!port->vphys_mask && !port->sas_address) + port->flags |= HBA_PORT_FLAG_DIRTY_PORT; + } +} + +/** + * _scsih_del_dirty_port_entries - delete dirty port entries from port list + * after host reset + *@ioc: per adapter object + * + */ +static void +_scsih_del_dirty_port_entries(struct MPT3SAS_ADAPTER *ioc) +{ + struct hba_port *port, *port_next; + + list_for_each_entry_safe(port, port_next, + &ioc->port_table_list, list) { + if (!(port->flags & HBA_PORT_FLAG_DIRTY_PORT) || + port->flags & HBA_PORT_FLAG_NEW_PORT) + continue; + + drsprintk(ioc, ioc_info(ioc, + "Deleting port table entry %p having Port: %d\t Phy_mask 0x%08x\n", + port, port->port_id, port->phy_mask)); + list_del(&port->list); + kfree(port); + } +} + +/** + * _scsih_sas_port_refresh - Update HBA port table after host reset + * @ioc: per adapter object + */ +static void +_scsih_sas_port_refresh(struct MPT3SAS_ADAPTER *ioc) +{ + u32 port_count = 0; + struct hba_port *port_table; + struct hba_port *port_table_entry; + struct hba_port *port_entry = NULL; + int i, j, count = 0, lcount = 0; + int ret; + u64 sas_addr; + + drsprintk(ioc, ioc_info(ioc, + "updating ports for sas_host(0x%016llx)\n", + (unsigned long long)ioc->sas_hba.sas_address)); + + port_table = kcalloc(ioc->sas_hba.num_phys, + sizeof(struct hba_port), GFP_KERNEL); + if (!port_table) + return; + + port_count = _scsih_get_port_table_after_reset(ioc, port_table); + if (!port_count) + return; + + drsprintk(ioc, ioc_info(ioc, "New Port table\n")); + for (j = 0; j < port_count; j++) + drsprintk(ioc, ioc_info(ioc, + "Port: %d\t Phy_mask 0x%08x\t sas_addr(0x%016llx)\n", + port_table[j].port_id, + port_table[j].phy_mask, port_table[j].sas_address)); + + list_for_each_entry(port_table_entry, &ioc->port_table_list, list) + port_table_entry->flags |= HBA_PORT_FLAG_DIRTY_PORT; + + drsprintk(ioc, ioc_info(ioc, "Old Port table\n")); + port_table_entry = NULL; + list_for_each_entry(port_table_entry, &ioc->port_table_list, list) { + drsprintk(ioc, ioc_info(ioc, + "Port: %d\t Phy_mask 0x%08x\t sas_addr(0x%016llx)\n", + port_table_entry->port_id, + port_table_entry->phy_mask, + port_table_entry->sas_address)); + } + + for (j = 0; j < port_count; j++) { + ret = _scsih_look_and_get_matched_port_entry(ioc, + &port_table[j], &port_entry, &count); + if (!port_entry) { + drsprintk(ioc, ioc_info(ioc, + "No Matched entry for sas_addr(0x%16llx), Port:%d\n", + port_table[j].sas_address, + port_table[j].port_id)); + continue; + } + + switch (ret) { + case MATCHED_WITH_ADDR_SUBPHYMASK_AND_PORT: + case MATCHED_WITH_ADDR_AND_SUBPHYMASK: + _scsih_add_or_del_phys_from_existing_port(ioc, + port_entry, port_table, j, port_count); + break; + case MATCHED_WITH_ADDR: + sas_addr = port_table[j].sas_address; + for (i = 0; i < port_count; i++) { + if (port_table[i].sas_address == sas_addr) + lcount++; + } + + if (count > 1 || lcount > 1) + port_entry = NULL; + else + _scsih_add_or_del_phys_from_existing_port(ioc, + port_entry, port_table, j, port_count); + } + + if (!port_entry) + continue; + + if (port_entry->port_id != port_table[j].port_id) + port_entry->port_id = port_table[j].port_id; + port_entry->flags &= ~HBA_PORT_FLAG_DIRTY_PORT; + port_entry->phy_mask = port_table[j].phy_mask; + } + + port_table_entry = NULL; +} + +/** + * _scsih_alloc_vphy - allocate virtual_phy object + * @ioc: per adapter object + * @port_id: Port ID number + * @phy_num: HBA Phy number + * + * Returns allocated virtual_phy object. + */ +static struct virtual_phy * +_scsih_alloc_vphy(struct MPT3SAS_ADAPTER *ioc, u8 port_id, u8 phy_num) +{ + struct virtual_phy *vphy; + struct hba_port *port; + + port = mpt3sas_get_port_by_id(ioc, port_id, 0); + if (!port) + return NULL; + + vphy = mpt3sas_get_vphy_by_phy(ioc, port, phy_num); + if (!vphy) { + vphy = kzalloc(sizeof(struct virtual_phy), GFP_KERNEL); + if (!vphy) + return NULL; + + /* + * Enable bit corresponding to HBA phy number on its + * parent hba_port object's vphys_mask field. + */ + port->vphys_mask |= (1 << phy_num); + vphy->phy_mask |= (1 << phy_num); + + INIT_LIST_HEAD(&port->vphys_list); + list_add_tail(&vphy->list, &port->vphys_list); + + ioc_info(ioc, + "vphy entry: %p, port id: %d, phy:%d is added to port's vphys_list\n", + vphy, port->port_id, phy_num); + } + return vphy; +} + +/** * _scsih_sas_host_refresh - refreshing sas host object contents * @ioc: per adapter object * Context: user @@ -5732,7 +6510,9 @@ _scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc) Mpi2ConfigReply_t mpi_reply; Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; u16 attached_handle; - u8 link_rate; + u8 link_rate, port_id; + struct hba_port *port; + Mpi2SasPhyPage0_t phy_pg0; dtmprintk(ioc, ioc_info(ioc, "updating handles for sas_host(0x%016llx)\n", @@ -5756,15 +6536,57 @@ _scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc) for (i = 0; i < ioc->sas_hba.num_phys ; i++) { link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4; if (i == 0) - ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> - PhyData[0].ControllerDevHandle); + ioc->sas_hba.handle = le16_to_cpu( + sas_iounit_pg0->PhyData[0].ControllerDevHandle); + port_id = sas_iounit_pg0->PhyData[i].Port; + if (!(mpt3sas_get_port_by_id(ioc, port_id, 0))) { + port = kzalloc(sizeof(struct hba_port), GFP_KERNEL); + if (!port) + goto out; + + port->port_id = port_id; + ioc_info(ioc, + "hba_port entry: %p, port: %d is added to hba_port list\n", + port, port->port_id); + if (ioc->shost_recovery) + port->flags = HBA_PORT_FLAG_NEW_PORT; + list_add_tail(&port->list, &ioc->port_table_list); + } + /* + * Check whether current Phy belongs to HBA vSES device or not. + */ + if (le32_to_cpu(sas_iounit_pg0->PhyData[i].ControllerPhyDeviceInfo) & + MPI2_SAS_DEVICE_INFO_SEP && + (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { + if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, + &phy_pg0, i))) { + ioc_err(ioc, + "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + goto out; + } + if (!(le32_to_cpu(phy_pg0.PhyInfo) & + MPI2_SAS_PHYINFO_VIRTUAL_PHY)) + continue; + /* + * Allocate a virtual_phy object for vSES device, if + * this vSES device is hot added. + */ + if (!_scsih_alloc_vphy(ioc, port_id, i)) + goto out; + ioc->sas_hba.phy[i].hba_vphy = 1; + } + ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. AttachedDevHandle); if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) link_rate = MPI2_SAS_NEG_LINK_RATE_1_5; + ioc->sas_hba.phy[i].port = + mpt3sas_get_port_by_id(ioc, port_id, 0); mpt3sas_transport_update_links(ioc, ioc->sas_hba.sas_address, - attached_handle, i, link_rate); + attached_handle, i, link_rate, + ioc->sas_hba.phy[i].port); } out: kfree(sas_iounit_pg0); @@ -5789,7 +6611,8 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) u16 ioc_status; u16 sz; u8 device_missing_delay; - u8 num_phys; + u8 num_phys, port_id; + struct hba_port *port; mpt3sas_config_get_number_hba_phys(ioc, &num_phys); if (!num_phys) { @@ -5882,8 +6705,40 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) if (i == 0) ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> PhyData[0].ControllerDevHandle); + + port_id = sas_iounit_pg0->PhyData[i].Port; + if (!(mpt3sas_get_port_by_id(ioc, port_id, 0))) { + port = kzalloc(sizeof(struct hba_port), GFP_KERNEL); + if (!port) + goto out; + + port->port_id = port_id; + ioc_info(ioc, + "hba_port entry: %p, port: %d is added to hba_port list\n", + port, port->port_id); + list_add_tail(&port->list, + &ioc->port_table_list); + } + + /* + * Check whether current Phy belongs to HBA vSES device or not. + */ + if ((le32_to_cpu(phy_pg0.PhyInfo) & + MPI2_SAS_PHYINFO_VIRTUAL_PHY) && + (phy_pg0.NegotiatedLinkRate >> 4) >= + MPI2_SAS_NEG_LINK_RATE_1_5) { + /* + * Allocate a virtual_phy object for vSES device. + */ + if (!_scsih_alloc_vphy(ioc, port_id, i)) + goto out; + ioc->sas_hba.phy[i].hba_vphy = 1; + } + ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; ioc->sas_hba.phy[i].phy_id = i; + ioc->sas_hba.phy[i].port = + mpt3sas_get_port_by_id(ioc, port_id, 0); mpt3sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i], phy_pg0, ioc->sas_hba.parent_dev); } @@ -5937,6 +6792,7 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) int i; unsigned long flags; struct _sas_port *mpt3sas_port = NULL; + u8 port_id; int rc = 0; @@ -5969,10 +6825,13 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) __FILE__, __LINE__, __func__); return -1; } + + port_id = expander_pg0.PhysicalPort; if (sas_address_parent != ioc->sas_hba.sas_address) { spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_expander = mpt3sas_scsih_expander_find_by_sas_address(ioc, - sas_address_parent); + sas_address_parent, + mpt3sas_get_port_by_id(ioc, port_id, 0)); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!sas_expander) { rc = _scsih_expander_add(ioc, parent_handle); @@ -5984,7 +6843,7 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_address = le64_to_cpu(expander_pg0.SASAddress); sas_expander = mpt3sas_scsih_expander_find_by_sas_address(ioc, - sas_address); + sas_address, mpt3sas_get_port_by_id(ioc, port_id, 0)); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (sas_expander) @@ -6002,6 +6861,13 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) sas_expander->num_phys = expander_pg0.NumPhys; sas_expander->sas_address_parent = sas_address_parent; sas_expander->sas_address = sas_address; + sas_expander->port = mpt3sas_get_port_by_id(ioc, port_id, 0); + if (!sas_expander->port) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + rc = -1; + goto out_fail; + } ioc_info(ioc, "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", handle, parent_handle, @@ -6020,7 +6886,7 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) INIT_LIST_HEAD(&sas_expander->sas_port_list); mpt3sas_port = mpt3sas_transport_port_add(ioc, handle, - sas_address_parent); + sas_address_parent, sas_expander->port); if (!mpt3sas_port) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -6028,6 +6894,7 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) goto out_fail; } sas_expander->parent_dev = &mpt3sas_port->rphy->dev; + sas_expander->rphy = mpt3sas_port->rphy; for (i = 0 ; i < sas_expander->num_phys ; i++) { if ((mpt3sas_config_get_expander_pg1(ioc, &mpi_reply, @@ -6039,6 +6906,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) } sas_expander->phy[i].handle = handle; sas_expander->phy[i].phy_id = i; + sas_expander->phy[i].port = + mpt3sas_get_port_by_id(ioc, port_id, 0); if ((mpt3sas_transport_add_expander_phy(ioc, &sas_expander->phy[i], expander_pg1, @@ -6066,7 +6935,7 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) if (mpt3sas_port) mpt3sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_address_parent); + sas_address_parent, sas_expander->port); kfree(sas_expander); return rc; } @@ -6077,7 +6946,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) * @sas_address: expander sas_address */ void -mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) +mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, + struct hba_port *port) { struct _sas_node *sas_expander; unsigned long flags; @@ -6085,9 +6955,12 @@ mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) if (ioc->shost_recovery) return; + if (!port) + return; + spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_expander = mpt3sas_scsih_expander_find_by_sas_address(ioc, - sas_address); + sas_address, port); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (sas_expander) _scsih_expander_node_remove(ioc, sas_expander); @@ -6210,7 +7083,7 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, { Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; - struct _sas_device *sas_device; + struct _sas_device *sas_device = NULL; struct _enclosure_node *enclosure_dev = NULL; u32 ioc_status; unsigned long flags; @@ -6218,6 +7091,7 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, struct scsi_target *starget; struct MPT3SAS_TARGET *sas_target_priv_data; u32 device_info; + struct hba_port *port; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) @@ -6240,8 +7114,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + port = mpt3sas_get_port_by_id(ioc, sas_device_pg0.PhysicalPort, 0); + if (!port) + goto out_unlock; sas_device = __mpt3sas_get_sdev_by_addr(ioc, - sas_address); + sas_address, port); if (!sas_device) goto out_unlock; @@ -6297,7 +7174,7 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, goto out_unlock; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_ublock_io_device(ioc, sas_address); + _scsih_ublock_io_device(ioc, sas_address, port); if (sas_device) sas_device_put(sas_device); @@ -6331,6 +7208,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u32 ioc_status; u64 sas_address; u32 device_info; + u8 port_id; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { @@ -6367,8 +7245,9 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, sas_device_pg0.AccessStatus)) return -1; + port_id = sas_device_pg0.PhysicalPort; sas_device = mpt3sas_get_sdev_by_addr(ioc, - sas_address); + sas_address, mpt3sas_get_port_by_id(ioc, port_id, 0)); if (sas_device) { clear_bit(handle, ioc->pend_os_device_add); sas_device_put(sas_device); @@ -6409,6 +7288,12 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, sas_device->phy = sas_device_pg0.PhyNum; sas_device->fast_path = (le16_to_cpu(sas_device_pg0.Flags) & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) ? 1 : 0; + sas_device->port = mpt3sas_get_port_by_id(ioc, port_id, 0); + if (!sas_device->port) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + goto out; + } if (le16_to_cpu(sas_device_pg0.Flags) & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { @@ -6442,6 +7327,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, else _scsih_sas_device_add(ioc, sas_device); +out: sas_device_put(sas_device); return 0; } @@ -6474,7 +7360,8 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, if (sas_device->starget && sas_device->starget->hostdata) { sas_target_priv_data = sas_device->starget->hostdata; sas_target_priv_data->deleted = 1; - _scsih_ublock_io_device(ioc, sas_device->sas_address); + _scsih_ublock_io_device(ioc, sas_device->sas_address, + sas_device->port); sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; } @@ -6482,7 +7369,8 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, if (!ioc->hide_drives) mpt3sas_transport_port_remove(ioc, sas_device->sas_address, - sas_device->sas_address_parent); + sas_device->sas_address_parent, + sas_device->port); ioc_info(ioc, "removing handle(0x%04x), sas_addr(0x%016llx)\n", sas_device->handle, (u64)sas_device->sas_address); @@ -6593,6 +7481,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, u64 sas_address; unsigned long flags; u8 link_rate, prev_link_rate; + struct hba_port *port; Mpi2EventDataSasTopologyChangeList_t *event_data = (Mpi2EventDataSasTopologyChangeList_t *) fw_event->event_data; @@ -6614,6 +7503,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, } parent_handle = le16_to_cpu(event_data->ExpanderDevHandle); + port = mpt3sas_get_port_by_id(ioc, event_data->PhysicalPort, 0); /* handle expander add */ if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) @@ -6626,6 +7516,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, if (sas_expander) { sas_address = sas_expander->sas_address; max_phys = sas_expander->num_phys; + port = sas_expander->port; } else if (parent_handle < ioc->sas_hba.num_phys) { sas_address = ioc->sas_hba.sas_address; max_phys = ioc->sas_hba.num_phys; @@ -6668,7 +7559,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, break; mpt3sas_transport_update_links(ioc, sas_address, - handle, phy_number, link_rate); + handle, phy_number, link_rate, port); if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) break; @@ -6687,7 +7578,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, break; mpt3sas_transport_update_links(ioc, sas_address, - handle, phy_number, link_rate); + handle, phy_number, link_rate, port); _scsih_add_device(ioc, handle, phy_number, 0); @@ -6702,7 +7593,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, /* handle expander removal */ if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && sas_expander) - mpt3sas_expander_remove(ioc, sas_address); + mpt3sas_expander_remove(ioc, sas_address, port); return 0; } @@ -6803,7 +7694,8 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_address = le64_to_cpu(event_data->SASAddress); sas_device = __mpt3sas_get_sdev_by_addr(ioc, - sas_address); + sas_address, + mpt3sas_get_port_by_id(ioc, event_data->PhysicalPort, 0)); if (!sas_device || !sas_device->starget) goto out; @@ -6952,7 +7844,7 @@ _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc, if (pcie_device->starget && pcie_device->starget->hostdata) { sas_target_priv_data = pcie_device->starget->hostdata; sas_target_priv_data->deleted = 1; - _scsih_ublock_io_device(ioc, pcie_device->wwid); + _scsih_ublock_io_device(ioc, pcie_device->wwid, NULL); sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; } @@ -7074,7 +7966,7 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); pcie_device_put(pcie_device); - _scsih_ublock_io_device(ioc, wwid); + _scsih_ublock_io_device(ioc, wwid, NULL); return; } @@ -8243,7 +9135,9 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) mpt3sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); + sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5, + mpt3sas_get_port_by_id(ioc, + sas_device_pg0.PhysicalPort, 0)); _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); _scsih_add_device(ioc, handle, 0, 1); @@ -8549,7 +9443,9 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) mpt3sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); + sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5, + mpt3sas_get_port_by_id(ioc, + sas_device_pg0.PhysicalPort, 0)); _scsih_add_device(ioc, handle, 0, 1); @@ -8674,6 +9570,8 @@ Mpi2SasDevicePage0_t *sas_device_pg0) struct _sas_device *sas_device = NULL; struct _enclosure_node *enclosure_dev = NULL; unsigned long flags; + struct hba_port *port = mpt3sas_get_port_by_id( + ioc, sas_device_pg0->PhysicalPort, 0); if (sas_device_pg0->EnclosureHandle) { enclosure_dev = @@ -8685,69 +9583,71 @@ Mpi2SasDevicePage0_t *sas_device_pg0) } spin_lock_irqsave(&ioc->sas_device_lock, flags); list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if ((sas_device->sas_address == le64_to_cpu( - sas_device_pg0->SASAddress)) && (sas_device->slot == - le16_to_cpu(sas_device_pg0->Slot))) { - sas_device->responding = 1; - starget = sas_device->starget; - if (starget && starget->hostdata) { - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->tm_busy = 0; - sas_target_priv_data->deleted = 0; - } else - sas_target_priv_data = NULL; - if (starget) { - starget_printk(KERN_INFO, starget, - "handle(0x%04x), sas_addr(0x%016llx)\n", - le16_to_cpu(sas_device_pg0->DevHandle), - (unsigned long long) - sas_device->sas_address); + if (sas_device->sas_address != le64_to_cpu( + sas_device_pg0->SASAddress)) + continue; + if (sas_device->slot != le16_to_cpu(sas_device_pg0->Slot)) + continue; + if (sas_device->port != port) + continue; + sas_device->responding = 1; + starget = sas_device->starget; + if (starget && starget->hostdata) { + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->tm_busy = 0; + sas_target_priv_data->deleted = 0; + } else + sas_target_priv_data = NULL; + if (starget) { + starget_printk(KERN_INFO, starget, + "handle(0x%04x), sas_addr(0x%016llx)\n", + le16_to_cpu(sas_device_pg0->DevHandle), + (unsigned long long) + sas_device->sas_address); - if (sas_device->enclosure_handle != 0) - starget_printk(KERN_INFO, starget, - "enclosure logical id(0x%016llx)," - " slot(%d)\n", - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); - } - if (le16_to_cpu(sas_device_pg0->Flags) & - MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { - sas_device->enclosure_level = - sas_device_pg0->EnclosureLevel; - memcpy(&sas_device->connector_name[0], - &sas_device_pg0->ConnectorName[0], 4); - } else { - sas_device->enclosure_level = 0; - sas_device->connector_name[0] = '\0'; - } + if (sas_device->enclosure_handle != 0) + starget_printk(KERN_INFO, starget, + "enclosure logical id(0x%016llx), slot(%d)\n", + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); + } + if (le16_to_cpu(sas_device_pg0->Flags) & + MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { + sas_device->enclosure_level = + sas_device_pg0->EnclosureLevel; + memcpy(&sas_device->connector_name[0], + &sas_device_pg0->ConnectorName[0], 4); + } else { + sas_device->enclosure_level = 0; + sas_device->connector_name[0] = '\0'; + } - sas_device->enclosure_handle = - le16_to_cpu(sas_device_pg0->EnclosureHandle); - sas_device->is_chassis_slot_valid = 0; - if (enclosure_dev) { - sas_device->enclosure_logical_id = le64_to_cpu( - enclosure_dev->pg0.EnclosureLogicalID); - if (le16_to_cpu(enclosure_dev->pg0.Flags) & - MPI2_SAS_ENCLS0_FLAGS_CHASSIS_SLOT_VALID) { - sas_device->is_chassis_slot_valid = 1; - sas_device->chassis_slot = - enclosure_dev->pg0.ChassisSlot; - } + sas_device->enclosure_handle = + le16_to_cpu(sas_device_pg0->EnclosureHandle); + sas_device->is_chassis_slot_valid = 0; + if (enclosure_dev) { + sas_device->enclosure_logical_id = le64_to_cpu( + enclosure_dev->pg0.EnclosureLogicalID); + if (le16_to_cpu(enclosure_dev->pg0.Flags) & + MPI2_SAS_ENCLS0_FLAGS_CHASSIS_SLOT_VALID) { + sas_device->is_chassis_slot_valid = 1; + sas_device->chassis_slot = + enclosure_dev->pg0.ChassisSlot; } + } - if (sas_device->handle == le16_to_cpu( - sas_device_pg0->DevHandle)) - goto out; - pr_info("\thandle changed from(0x%04x)!!!\n", - sas_device->handle); - sas_device->handle = le16_to_cpu( - sas_device_pg0->DevHandle); - if (sas_target_priv_data) - sas_target_priv_data->handle = - le16_to_cpu(sas_device_pg0->DevHandle); + if (sas_device->handle == le16_to_cpu( + sas_device_pg0->DevHandle)) goto out; - } + pr_info("\thandle changed from(0x%04x)!!!\n", + sas_device->handle); + sas_device->handle = le16_to_cpu( + sas_device_pg0->DevHandle); + if (sas_target_priv_data) + sas_target_priv_data->handle = + le16_to_cpu(sas_device_pg0->DevHandle); + goto out; } out: spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -9098,6 +9998,8 @@ _scsih_mark_responding_expander(struct MPT3SAS_ADAPTER *ioc, u16 handle = le16_to_cpu(expander_pg0->DevHandle); u16 enclosure_handle = le16_to_cpu(expander_pg0->EnclosureHandle); u64 sas_address = le64_to_cpu(expander_pg0->SASAddress); + struct hba_port *port = mpt3sas_get_port_by_id( + ioc, expander_pg0->PhysicalPort, 0); if (enclosure_handle) enclosure_dev = @@ -9108,6 +10010,8 @@ _scsih_mark_responding_expander(struct MPT3SAS_ADAPTER *ioc, list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { if (sas_expander->sas_address != sas_address) continue; + if (sas_expander->port != port) + continue; sas_expander->responding = 1; if (enclosure_dev) { @@ -9147,6 +10051,7 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc) u16 ioc_status; u64 sas_address; u16 handle; + u8 port; ioc_info(ioc, "search for expanders: start\n"); @@ -9164,9 +10069,12 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc) handle = le16_to_cpu(expander_pg0.DevHandle); sas_address = le64_to_cpu(expander_pg0.SASAddress); - pr_info("\texpander present: handle(0x%04x), sas_addr(0x%016llx)\n", - handle, - (unsigned long long)sas_address); + port = expander_pg0.PhysicalPort; + pr_info( + "\texpander present: handle(0x%04x), sas_addr(0x%016llx), port:%d\n", + handle, (unsigned long long)sas_address, + (ioc->multipath_on_hba ? + port : MULTIPATH_DISABLED_PORT_ID)); _scsih_mark_responding_expander(ioc, &expander_pg0); } @@ -9288,7 +10196,8 @@ _scsih_refresh_expander_links(struct MPT3SAS_ADAPTER *ioc, mpt3sas_transport_update_links(ioc, sas_expander->sas_address, le16_to_cpu(expander_pg1.AttachedDevHandle), i, - expander_pg1.NegotiatedLinkRate >> 4); + expander_pg1.NegotiatedLinkRate >> 4, + sas_expander->port); } } @@ -9307,7 +10216,7 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) Mpi2RaidPhysDiskPage0_t pd_pg0; Mpi2EventIrConfigElement_t element; Mpi2ConfigReply_t mpi_reply; - u8 phys_disk_num; + u8 phys_disk_num, port_id; u16 ioc_status; u16 handle, parent_handle; u64 sas_address; @@ -9337,8 +10246,10 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) } handle = le16_to_cpu(expander_pg0.DevHandle); spin_lock_irqsave(&ioc->sas_node_lock, flags); + port_id = expander_pg0.PhysicalPort; expander_device = mpt3sas_scsih_expander_find_by_sas_address( - ioc, le64_to_cpu(expander_pg0.SASAddress)); + ioc, le64_to_cpu(expander_pg0.SASAddress), + mpt3sas_get_port_by_id(ioc, port_id, 0)); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (expander_device) _scsih_refresh_expander_links(ioc, expander_device, @@ -9397,9 +10308,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_info(ioc, "\tBEFORE adding phys disk: handle (0x%04x), sas_addr(0x%016llx)\n", handle, (u64)le64_to_cpu(sas_device_pg0.SASAddress)); + port_id = sas_device_pg0.PhysicalPort; mpt3sas_transport_update_links(ioc, sas_address, handle, sas_device_pg0.PhyNum, - MPI2_SAS_NEG_LINK_RATE_1_5); + MPI2_SAS_NEG_LINK_RATE_1_5, + mpt3sas_get_port_by_id(ioc, port_id, 0)); set_bit(handle, ioc->pd_handles); retry_count = 0; /* This will retry adding the end device. @@ -9485,8 +10398,10 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) if (!(_scsih_is_end_device( le32_to_cpu(sas_device_pg0.DeviceInfo)))) continue; + port_id = sas_device_pg0.PhysicalPort; sas_device = mpt3sas_get_sdev_by_addr(ioc, - le64_to_cpu(sas_device_pg0.SASAddress)); + le64_to_cpu(sas_device_pg0.SASAddress), + mpt3sas_get_port_by_id(ioc, port_id, 0)); if (sas_device) { sas_device_put(sas_device); continue; @@ -9497,7 +10412,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) handle, (u64)le64_to_cpu(sas_device_pg0.SASAddress)); mpt3sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); + sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5, + mpt3sas_get_port_by_id(ioc, port_id, 0)); retry_count = 0; /* This will retry adding the end device. * _scsih_add_device() will decide on retries and @@ -9601,6 +10517,10 @@ mpt3sas_scsih_reset_done_handler(struct MPT3SAS_ADAPTER *ioc) dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__)); if ((!ioc->is_driver_loading) && !(disable_discovery > 0 && !ioc->sas_hba.num_phys)) { + if (ioc->multipath_on_hba) { + _scsih_sas_port_refresh(ioc); + _scsih_update_vphys_after_reset(ioc); + } _scsih_prep_device_scan(ioc); _scsih_create_enclosure_list_after_reset(ioc); _scsih_search_responding_sas_devices(ioc); @@ -9648,6 +10568,8 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) ssleep(1); } _scsih_remove_unresponding_devices(ioc); + _scsih_del_dirty_vphy(ioc); + _scsih_del_dirty_port_entries(ioc); _scsih_scan_for_devices_after_reset(ioc); _scsih_set_nvme_max_shutdown_latency(ioc); break; @@ -9930,21 +10852,25 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) mpt3sas_device_remove_by_sas_address(ioc, - mpt3sas_port->remote_identify.sas_address); + mpt3sas_port->remote_identify.sas_address, + mpt3sas_port->hba_port); else if (mpt3sas_port->remote_identify.device_type == SAS_EDGE_EXPANDER_DEVICE || mpt3sas_port->remote_identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) mpt3sas_expander_remove(ioc, - mpt3sas_port->remote_identify.sas_address); + mpt3sas_port->remote_identify.sas_address, + mpt3sas_port->hba_port); } mpt3sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_expander->sas_address_parent); + sas_expander->sas_address_parent, sas_expander->port); - ioc_info(ioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx)\n", - sas_expander->handle, (unsigned long long) - sas_expander->sas_address); + ioc_info(ioc, + "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n", + sas_expander->handle, (unsigned long long) + sas_expander->sas_address, + sas_expander->port->port_id); spin_lock_irqsave(&ioc->sas_node_lock, flags); list_del(&sas_expander->list); @@ -10136,6 +11062,7 @@ static void scsih_remove(struct pci_dev *pdev) struct workqueue_struct *wq; unsigned long flags; Mpi2ConfigReply_t mpi_reply; + struct hba_port *port, *port_next; if (_scsih_get_shost_and_ioc(pdev, &shost, &ioc)) return; @@ -10189,13 +11116,21 @@ static void scsih_remove(struct pci_dev *pdev) if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) mpt3sas_device_remove_by_sas_address(ioc, - mpt3sas_port->remote_identify.sas_address); + mpt3sas_port->remote_identify.sas_address, + mpt3sas_port->hba_port); else if (mpt3sas_port->remote_identify.device_type == SAS_EDGE_EXPANDER_DEVICE || mpt3sas_port->remote_identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) mpt3sas_expander_remove(ioc, - mpt3sas_port->remote_identify.sas_address); + mpt3sas_port->remote_identify.sas_address, + mpt3sas_port->hba_port); + } + + list_for_each_entry_safe(port, port_next, + &ioc->port_table_list, list) { + list_del(&port->list); + kfree(port); } /* free phys attached to the sas_host */ @@ -10277,6 +11212,7 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc) unsigned long flags; int rc; int tid; + struct hba_port *port; /* no Bios, return immediately */ if (!ioc->bios_pg3.BiosVersion) @@ -10318,19 +11254,24 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc) handle = sas_device->handle; sas_address_parent = sas_device->sas_address_parent; sas_address = sas_device->sas_address; + port = sas_device->port; list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (ioc->hide_drives) return; + + if (!port) + return; + if (!mpt3sas_transport_port_add(ioc, handle, - sas_address_parent)) { + sas_address_parent, port)) { _scsih_sas_device_remove(ioc, sas_device); } else if (!sas_device->starget) { if (!ioc->is_driver_loading) { mpt3sas_transport_port_remove(ioc, sas_address, - sas_address_parent); + sas_address_parent, port); _scsih_sas_device_remove(ioc, sas_device); } } @@ -10418,7 +11359,7 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) while ((sas_device = get_next_sas_device(ioc))) { if (!mpt3sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { + sas_device->sas_address_parent, sas_device->port)) { _scsih_sas_device_remove(ioc, sas_device); sas_device_put(sas_device); continue; @@ -10432,7 +11373,8 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) if (!ioc->is_driver_loading) { mpt3sas_transport_port_remove(ioc, sas_device->sas_address, - sas_device->sas_address_parent); + sas_device->sas_address_parent, + sas_device->port); _scsih_sas_device_remove(ioc, sas_device); sas_device_put(sas_device); continue; @@ -10866,6 +11808,12 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; break; } + + if (multipath_on_hba == -1 || multipath_on_hba == 0) + ioc->multipath_on_hba = 0; + else + ioc->multipath_on_hba = 1; + break; case MPI25_VERSION: case MPI26_VERSION: @@ -10927,6 +11875,23 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->combined_reply_index_count = MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT_G3; } + + switch (ioc->is_gen35_ioc) { + case 0: + if (multipath_on_hba == -1 || multipath_on_hba == 0) + ioc->multipath_on_hba = 0; + else + ioc->multipath_on_hba = 1; + break; + case 1: + if (multipath_on_hba == -1 || multipath_on_hba > 0) + ioc->multipath_on_hba = 1; + else + ioc->multipath_on_hba = 0; + default: + break; + } + break; default: return -ENODEV; @@ -10987,6 +11952,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&ioc->delayed_event_ack_list); INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); INIT_LIST_HEAD(&ioc->reply_queue_list); + INIT_LIST_HEAD(&ioc->port_table_list); sprintf(ioc->name, "%s_cm%d", ioc->driver_name, ioc->id); @@ -11084,20 +12050,18 @@ out_add_shost_fail: return rv; } -#ifdef CONFIG_PM /** * scsih_suspend - power management suspend main entry point - * @pdev: PCI device struct - * @state: PM state change to (usually PCI_D3) + * @dev: Device struct * * Return: 0 success, anything else error. */ -static int -scsih_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused +scsih_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct Scsi_Host *shost; struct MPT3SAS_ADAPTER *ioc; - pci_power_t device_state; int rc; rc = _scsih_get_shost_and_ioc(pdev, &shost, &ioc); @@ -11108,25 +12072,23 @@ scsih_suspend(struct pci_dev *pdev, pm_message_t state) flush_scheduled_work(); scsi_block_requests(shost); _scsih_nvme_shutdown(ioc); - device_state = pci_choose_state(pdev, state); - ioc_info(ioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n", - pdev, pci_name(pdev), device_state); + ioc_info(ioc, "pdev=0x%p, slot=%s, entering operating state\n", + pdev, pci_name(pdev)); - pci_save_state(pdev); mpt3sas_base_free_resources(ioc); - pci_set_power_state(pdev, device_state); return 0; } /** * scsih_resume - power management resume main entry point - * @pdev: PCI device struct + * @dev: Device struct * * Return: 0 success, anything else error. */ -static int -scsih_resume(struct pci_dev *pdev) +static int __maybe_unused +scsih_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct Scsi_Host *shost; struct MPT3SAS_ADAPTER *ioc; pci_power_t device_state = pdev->current_state; @@ -11139,9 +12101,6 @@ scsih_resume(struct pci_dev *pdev) ioc_info(ioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n", pdev, pci_name(pdev), device_state); - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); ioc->pdev = pdev; r = mpt3sas_base_map_resources(ioc); if (r) @@ -11152,7 +12111,6 @@ scsih_resume(struct pci_dev *pdev) mpt3sas_base_start_watchdog(ioc); return 0; } -#endif /* CONFIG_PM */ /** * scsih_pci_error_detected - Called when a PCI error is detected. @@ -11454,6 +12412,8 @@ static struct pci_error_handlers _mpt3sas_err_handler = { .resume = scsih_pci_resume, }; +static SIMPLE_DEV_PM_OPS(scsih_pm_ops, scsih_suspend, scsih_resume); + static struct pci_driver mpt3sas_driver = { .name = MPT3SAS_DRIVER_NAME, .id_table = mpt3sas_pci_table, @@ -11461,10 +12421,7 @@ static struct pci_driver mpt3sas_driver = { .remove = scsih_remove, .shutdown = scsih_shutdown, .err_handler = &_mpt3sas_err_handler, -#ifdef CONFIG_PM - .suspend = scsih_suspend, - .resume = scsih_resume, -#endif + .driver.pm = &scsih_pm_ops, }; /** diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 6ec5b7f33dfd..6f4708224755 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -61,9 +61,28 @@ #include "mpt3sas_base.h" /** + * _transport_get_port_id_by_sas_phy - get zone's port id that Phy belong to + * @phy - sas_phy object + * + * Return Port number + */ +static inline u8 +_transport_get_port_id_by_sas_phy(struct sas_phy *phy) +{ + u8 port_id = 0xFF; + struct hba_port *port = phy->hostdata; + + if (port) + port_id = port->port_id; + + return port_id; +} + +/** * _transport_sas_node_find_by_sas_address - sas node search * @ioc: per adapter object * @sas_address: sas address of expander or sas host + * @port: hba port entry * Context: Calling function should acquire ioc->sas_node_lock. * * Search for either hba phys or expander device based on handle, then returns @@ -71,13 +90,56 @@ */ static struct _sas_node * _transport_sas_node_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, - u64 sas_address) + u64 sas_address, struct hba_port *port) { if (ioc->sas_hba.sas_address == sas_address) return &ioc->sas_hba; else return mpt3sas_scsih_expander_find_by_sas_address(ioc, - sas_address); + sas_address, port); +} + +/** + * _transport_get_port_id_by_rphy - Get Port number from rphy object + * @ioc: per adapter object + * @rphy: sas_rphy object + * + * Returns Port number. + */ +static u8 +_transport_get_port_id_by_rphy(struct MPT3SAS_ADAPTER *ioc, + struct sas_rphy *rphy) +{ + struct _sas_node *sas_expander; + struct _sas_device *sas_device; + unsigned long flags; + u8 port_id = 0xFF; + + if (!rphy) + return port_id; + + if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE || + rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) { + spin_lock_irqsave(&ioc->sas_node_lock, flags); + list_for_each_entry(sas_expander, + &ioc->sas_expander_list, list) { + if (sas_expander->rphy == rphy) { + port_id = sas_expander->port->port_id; + break; + } + } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + } else if (rphy->identify.device_type == SAS_END_DEVICE) { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy); + if (sas_device) { + port_id = sas_device->port->port_id; + sas_device_put(sas_device); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } + + return port_id; } /** @@ -288,7 +350,7 @@ struct rep_manu_reply { */ static int _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, - u64 sas_address, struct sas_expander_device *edev) + u64 sas_address, struct sas_expander_device *edev, u8 port_id) { Mpi2SmpPassthroughRequest_t *mpi_request; Mpi2SmpPassthroughReply_t *mpi_reply; @@ -355,7 +417,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; + mpi_request->PhysicalPort = port_id; mpi_request->SASAddress = cpu_to_le64(sas_address); mpi_request->RequestDataLength = cpu_to_le16(data_out_sz); psge = &mpi_request->SGL; @@ -439,6 +501,7 @@ _transport_delete_port(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt3sas_port) { u64 sas_address = mpt3sas_port->remote_identify.sas_address; + struct hba_port *port = mpt3sas_port->hba_port; enum sas_device_type device_type = mpt3sas_port->remote_identify.device_type; @@ -448,10 +511,11 @@ _transport_delete_port(struct MPT3SAS_ADAPTER *ioc, ioc->logging_level |= MPT_DEBUG_TRANSPORT; if (device_type == SAS_END_DEVICE) - mpt3sas_device_remove_by_sas_address(ioc, sas_address); + mpt3sas_device_remove_by_sas_address(ioc, + sas_address, port); else if (device_type == SAS_EDGE_EXPANDER_DEVICE || device_type == SAS_FANOUT_EXPANDER_DEVICE) - mpt3sas_expander_remove(ioc, sas_address); + mpt3sas_expander_remove(ioc, sas_address, port); ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; } @@ -500,16 +564,17 @@ _transport_add_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt3sas_port, } /** - * _transport_add_phy_to_an_existing_port - adding new phy to existing port + * mpt3sas_transport_add_phy_to_an_existing_port - adding new phy to existing port * @ioc: per adapter object * @sas_node: sas node object (either expander or sas host) * @mpt3sas_phy: mpt3sas per phy object * @sas_address: sas address of device/expander were phy needs to be added to + * @port: hba port entry */ -static void -_transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc, +void +mpt3sas_transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy, - u64 sas_address) + u64 sas_address, struct hba_port *port) { struct _sas_port *mpt3sas_port; struct _sas_phy *phy_srch; @@ -517,11 +582,16 @@ _transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc, if (mpt3sas_phy->phy_belongs_to_port == 1) return; + if (!port) + return; + list_for_each_entry(mpt3sas_port, &sas_node->sas_port_list, port_list) { if (mpt3sas_port->remote_identify.sas_address != sas_address) continue; + if (mpt3sas_port->hba_port != port) + continue; list_for_each_entry(phy_srch, &mpt3sas_port->phy_list, port_siblings) { if (phy_srch == mpt3sas_phy) @@ -534,13 +604,13 @@ _transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc, } /** - * _transport_del_phy_from_an_existing_port - delete phy from existing port + * mpt3sas_transport_del_phy_from_an_existing_port - delete phy from existing port * @ioc: per adapter object * @sas_node: sas node object (either expander or sas host) * @mpt3sas_phy: mpt3sas per phy object */ -static void -_transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc, +void +mpt3sas_transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy) { struct _sas_port *mpt3sas_port, *next; @@ -556,7 +626,11 @@ _transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc, if (phy_srch != mpt3sas_phy) continue; - if (mpt3sas_port->num_phys == 1) + /* + * Don't delete port during host reset, + * just delete phy. + */ + if (mpt3sas_port->num_phys == 1 && !ioc->shost_recovery) _transport_delete_port(ioc, mpt3sas_port); else _transport_delete_phy(ioc, mpt3sas_port, @@ -571,21 +645,24 @@ _transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc, * @ioc: per adapter object * @sas_node: sas node object (either expander or sas host) * @sas_address: sas address of device being added + * @port: hba port entry * * See the explanation above from _transport_delete_duplicate_port */ static void _transport_sanity_check(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, - u64 sas_address) + u64 sas_address, struct hba_port *port) { int i; for (i = 0; i < sas_node->num_phys; i++) { if (sas_node->phy[i].remote_identify.sas_address != sas_address) continue; + if (sas_node->phy[i].port != port) + continue; if (sas_node->phy[i].phy_belongs_to_port == 1) - _transport_del_phy_from_an_existing_port(ioc, sas_node, - &sas_node->phy[i]); + mpt3sas_transport_del_phy_from_an_existing_port(ioc, + sas_node, &sas_node->phy[i]); } } @@ -594,6 +671,7 @@ _transport_sanity_check(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, * @ioc: per adapter object * @handle: handle of attached device * @sas_address: sas address of parent expander or sas host + * @port: hba port entry * Context: This function will acquire ioc->sas_node_lock. * * Adding new port object to the sas_node->sas_port_list. @@ -602,7 +680,7 @@ _transport_sanity_check(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, */ struct _sas_port * mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, - u64 sas_address) + u64 sas_address, struct hba_port *hba_port) { struct _sas_phy *mpt3sas_phy, *next; struct _sas_port *mpt3sas_port; @@ -612,6 +690,13 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, struct _sas_device *sas_device = NULL; int i; struct sas_port *port; + struct virtual_phy *vphy = NULL; + + if (!hba_port) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return NULL; + } mpt3sas_port = kzalloc(sizeof(struct _sas_port), GFP_KERNEL); @@ -624,7 +709,8 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, INIT_LIST_HEAD(&mpt3sas_port->port_list); INIT_LIST_HEAD(&mpt3sas_port->phy_list); spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); + sas_node = _transport_sas_node_find_by_sas_address(ioc, + sas_address, hba_port); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!sas_node) { @@ -646,16 +732,32 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, goto out_fail; } + mpt3sas_port->hba_port = hba_port; _transport_sanity_check(ioc, sas_node, - mpt3sas_port->remote_identify.sas_address); + mpt3sas_port->remote_identify.sas_address, hba_port); for (i = 0; i < sas_node->num_phys; i++) { if (sas_node->phy[i].remote_identify.sas_address != mpt3sas_port->remote_identify.sas_address) continue; + if (sas_node->phy[i].port != hba_port) + continue; list_add_tail(&sas_node->phy[i].port_siblings, &mpt3sas_port->phy_list); mpt3sas_port->num_phys++; + if (sas_node->handle <= ioc->sas_hba.num_phys) { + if (!sas_node->phy[i].hba_vphy) { + hba_port->phy_mask |= (1 << i); + continue; + } + + vphy = mpt3sas_get_vphy_by_phy(ioc, hba_port, i); + if (!vphy) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + goto out_fail; + } + } } if (!mpt3sas_port->num_phys) { @@ -664,6 +766,18 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, goto out_fail; } + if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { + sas_device = mpt3sas_get_sdev_by_addr(ioc, + mpt3sas_port->remote_identify.sas_address, + mpt3sas_port->hba_port); + if (!sas_device) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + goto out_fail; + } + sas_device->pend_sas_rphy_add = 1; + } + if (!sas_node->parent_dev) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -686,29 +800,31 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, mpt3sas_phy->phy_id); sas_port_add_phy(port, mpt3sas_phy->phy); mpt3sas_phy->phy_belongs_to_port = 1; + mpt3sas_phy->port = hba_port; } mpt3sas_port->port = port; - if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) + if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { rphy = sas_end_device_alloc(port); - else + sas_device->rphy = rphy; + if (sas_node->handle <= ioc->sas_hba.num_phys) { + if (!vphy) + hba_port->sas_address = + sas_device->sas_address; + else + vphy->sas_address = + sas_device->sas_address; + } + } else { rphy = sas_expander_alloc(port, mpt3sas_port->remote_identify.device_type); + if (sas_node->handle <= ioc->sas_hba.num_phys) + hba_port->sas_address = + mpt3sas_port->remote_identify.sas_address; + } rphy->identify = mpt3sas_port->remote_identify; - if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { - sas_device = mpt3sas_get_sdev_by_addr(ioc, - mpt3sas_port->remote_identify.sas_address); - if (!sas_device) { - dfailprintk(ioc, - ioc_info(ioc, "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__)); - goto out_fail; - } - sas_device->pend_sas_rphy_add = 1; - } - if ((sas_rphy_add(rphy))) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -735,7 +851,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) _transport_expander_report_manufacture(ioc, mpt3sas_port->remote_identify.sas_address, - rphy_to_expander_device(rphy)); + rphy_to_expander_device(rphy), hba_port->port_id); return mpt3sas_port; out_fail: @@ -751,6 +867,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, * @ioc: per adapter object * @sas_address: sas address of attached device * @sas_address_parent: sas address of parent expander or sas host + * @port: hba port entry * Context: This function will acquire ioc->sas_node_lock. * * Removing object and freeing associated memory from the @@ -758,7 +875,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, */ void mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, - u64 sas_address_parent) + u64 sas_address_parent, struct hba_port *port) { int i; unsigned long flags; @@ -766,10 +883,15 @@ mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, struct _sas_node *sas_node; u8 found = 0; struct _sas_phy *mpt3sas_phy, *next_phy; + struct hba_port *hba_port_next, *hba_port = NULL; + struct virtual_phy *vphy, *vphy_next = NULL; + + if (!port) + return; spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_node = _transport_sas_node_find_by_sas_address(ioc, - sas_address_parent); + sas_address_parent, port); if (!sas_node) { spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return; @@ -778,6 +900,8 @@ mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, port_list) { if (mpt3sas_port->remote_identify.sas_address != sas_address) continue; + if (mpt3sas_port->hba_port != port) + continue; found = 1; list_del(&mpt3sas_port->port_list); goto out; @@ -788,6 +912,61 @@ mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, return; } + if (sas_node->handle <= ioc->sas_hba.num_phys && + (ioc->multipath_on_hba)) { + if (port->vphys_mask) { + list_for_each_entry_safe(vphy, vphy_next, + &port->vphys_list, list) { + if (vphy->sas_address != sas_address) + continue; + ioc_info(ioc, + "remove vphy entry: %p of port:%p,from %d port's vphys list\n", + vphy, port, port->port_id); + port->vphys_mask &= ~vphy->phy_mask; + list_del(&vphy->list); + kfree(vphy); + } + } + + list_for_each_entry_safe(hba_port, hba_port_next, + &ioc->port_table_list, list) { + if (hba_port != port) + continue; + /* + * Delete hba_port object if + * - hba_port object's sas address matches with current + * removed device's sas address and no vphy's + * associated with it. + * - Current removed device is a vSES device and + * none of the other direct attached device have + * this vSES device's port number (hence hba_port + * object sas_address field will be zero). + */ + if ((hba_port->sas_address == sas_address || + !hba_port->sas_address) && !hba_port->vphys_mask) { + ioc_info(ioc, + "remove hba_port entry: %p port: %d from hba_port list\n", + hba_port, hba_port->port_id); + list_del(&hba_port->list); + kfree(hba_port); + } else if (hba_port->sas_address == sas_address && + hba_port->vphys_mask) { + /* + * Current removed device is a non vSES device + * and a vSES device has the same port number + * as of current device's port number. Hence + * only clear the sas_address filed, don't + * delete the hba_port object. + */ + ioc_info(ioc, + "clearing sas_address from hba_port entry: %p port: %d from hba_port list\n", + hba_port, hba_port->port_id); + port->sas_address = 0; + } + break; + } + } + for (i = 0; i < sas_node->num_phys; i++) { if (sas_node->phy[i].remote_identify.sas_address == sas_address) memset(&sas_node->phy[i].remote_identify, 0 , @@ -864,6 +1043,7 @@ mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); phy->maximum_linkrate = _transport_convert_phy_link_rate( phy_pg0.ProgrammedLinkRate >> 4); + phy->hostdata = mpt3sas_phy->port; if ((sas_phy_add(phy))) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -934,6 +1114,7 @@ mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); phy->maximum_linkrate = _transport_convert_phy_link_rate( expander_pg1.ProgrammedLinkRate >> 4); + phy->hostdata = mpt3sas_phy->port; if ((sas_phy_add(phy))) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -961,20 +1142,26 @@ mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy * @handle: attached device handle * @phy_number: phy number * @link_rate: new link rate + * @port: hba port entry + * + * Return nothing. */ void mpt3sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc, - u64 sas_address, u16 handle, u8 phy_number, u8 link_rate) + u64 sas_address, u16 handle, u8 phy_number, u8 link_rate, + struct hba_port *port) { unsigned long flags; struct _sas_node *sas_node; struct _sas_phy *mpt3sas_phy; + struct hba_port *hba_port = NULL; if (ioc->shost_recovery || ioc->pci_error_recovery) return; spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); + sas_node = _transport_sas_node_find_by_sas_address(ioc, + sas_address, port); if (!sas_node) { spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return; @@ -986,8 +1173,19 @@ mpt3sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc, if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { _transport_set_identify(ioc, handle, &mpt3sas_phy->remote_identify); - _transport_add_phy_to_an_existing_port(ioc, sas_node, - mpt3sas_phy, mpt3sas_phy->remote_identify.sas_address); + if ((sas_node->handle <= ioc->sas_hba.num_phys) && + (ioc->multipath_on_hba)) { + list_for_each_entry(hba_port, + &ioc->port_table_list, list) { + if (hba_port->sas_address == sas_address && + hba_port == port) + hba_port->phy_mask |= + (1 << mpt3sas_phy->phy_id); + } + } + mpt3sas_transport_add_phy_to_an_existing_port(ioc, sas_node, + mpt3sas_phy, mpt3sas_phy->remote_identify.sas_address, + port); } else memset(&mpt3sas_phy->remote_identify, 0 , sizeof(struct sas_identify)); @@ -1122,7 +1320,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; + mpi_request->PhysicalPort = _transport_get_port_id_by_sas_phy(phy); mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); @@ -1212,10 +1410,13 @@ _transport_get_linkerrors(struct sas_phy *phy) unsigned long flags; Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage1_t phy_pg1; + struct hba_port *port = phy->hostdata; + int port_id = port->port_id; spin_lock_irqsave(&ioc->sas_node_lock, flags); if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { + phy->identify.sas_address, + mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) { spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return -EINVAL; } @@ -1265,8 +1466,7 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt3sas_get_sdev_by_addr(ioc, - rphy->identify.sas_address); + sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy); if (sas_device) { *identifier = sas_device->enclosure_logical_id; rc = 0; @@ -1295,8 +1495,7 @@ _transport_get_bay_identifier(struct sas_rphy *rphy) int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt3sas_get_sdev_by_addr(ioc, - rphy->identify.sas_address); + sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy); if (sas_device) { rc = sas_device->slot; sas_device_put(sas_device); @@ -1417,7 +1616,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; + mpi_request->PhysicalPort = _transport_get_port_id_by_sas_phy(phy); mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); @@ -1499,11 +1698,14 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy); Mpi2SasIoUnitControlReply_t mpi_reply; Mpi2SasIoUnitControlRequest_t mpi_request; + struct hba_port *port = phy->hostdata; + int port_id = port->port_id; unsigned long flags; spin_lock_irqsave(&ioc->sas_node_lock, flags); if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { + phy->identify.sas_address, + mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) { spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return -EINVAL; } @@ -1556,10 +1758,13 @@ _transport_phy_enable(struct sas_phy *phy, int enable) int rc = 0; unsigned long flags; int i, discovery_active; + struct hba_port *port = phy->hostdata; + int port_id = port->port_id; spin_lock_irqsave(&ioc->sas_node_lock, flags); if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { + phy->identify.sas_address, + mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) { spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return -EINVAL; } @@ -1693,10 +1898,13 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) int i; int rc = 0; unsigned long flags; + struct hba_port *port = phy->hostdata; + int port_id = port->port_id; spin_lock_irqsave(&ioc->sas_node_lock, flags); if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { + phy->identify.sas_address, + mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) { spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return -EINVAL; } @@ -1898,7 +2106,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; + mpi_request->PhysicalPort = _transport_get_port_id_by_rphy(ioc, rphy); mpi_request->SASAddress = (rphy) ? cpu_to_le64(rphy->identify.sas_address) : cpu_to_le64(ioc->sas_hba.sas_address); diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h b/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h new file mode 100644 index 000000000000..5f3328f011a2 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * This is the Fusion MPT base driver providing common API layer interface + * to store diag trigger values into persistent driver triggers pages + * for MPT (Message Passing Technology) based controllers. + * + * Copyright (C) 2020 Broadcom Inc. + * + * Authors: Broadcom Inc. + * Sreekanth Reddy <sreekanth.reddy@broadcom.com> + * + * Send feedback to : MPT-FusionLinux.pdl@broadcom.com) + */ + +#include "mpi/mpi2_cnfg.h" + +#ifndef MPI2_TRIGGER_PAGES_H +#define MPI2_TRIGGER_PAGES_H + +#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER (0xE0) +#define MPI26_DRIVER_TRIGGER_PAGE0_PAGEVERSION (0x01) +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_0 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 TriggerFlags; /* 0x08 */ + U16 Reserved0xA; /* 0x0A */ + U32 Reserved0xC[61]; /* 0x0C */ +} _MPI26_CONFIG_PAGE_DRIVER_TIGGER_0, Mpi26DriverTriggerPage0_t; + +/* Trigger Flags */ +#define MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID (0x0001) +#define MPI26_DRIVER_TRIGGER0_FLAG_MPI_EVENT_TRIGGER_VALID (0x0002) +#define MPI26_DRIVER_TRIGGER0_FLAG_SCSI_SENSE_TRIGGER_VALID (0x0004) +#define MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID (0x0008) + +#define MPI26_DRIVER_TRIGGER_PAGE1_PAGEVERSION (0x01) +typedef struct _MPI26_DRIVER_MASTER_TIGGER_ENTRY { + U32 MasterTriggerFlags; +} MPI26_DRIVER_MASTER_TIGGER_ENTRY; + +#define MPI26_MAX_MASTER_TRIGGERS (1) +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_1 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 NumMasterTrigger; /* 0x08 */ + U16 Reserved0xA; /* 0x0A */ + MPI26_DRIVER_MASTER_TIGGER_ENTRY MasterTriggers[MPI26_MAX_MASTER_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TIGGER_1, Mpi26DriverTriggerPage1_t; + +#define MPI26_DRIVER_TRIGGER_PAGE2_PAGEVERSION (0x01) +typedef struct _MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY { + U16 MPIEventCode; /* 0x00 */ + U16 MPIEventCodeSpecific; /* 0x02 */ +} MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY; + +#define MPI26_MAX_MPI_EVENT_TRIGGERS (20) +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_2 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 NumMPIEventTrigger; /* 0x08 */ + U16 Reserved0xA; /* 0x0A */ + MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY MPIEventTriggers[MPI26_MAX_MPI_EVENT_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TIGGER_2, Mpi26DriverTriggerPage2_t; + +#define MPI26_DRIVER_TRIGGER_PAGE3_PAGEVERSION (0x01) +typedef struct _MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY { + U8 ASCQ; /* 0x00 */ + U8 ASC; /* 0x01 */ + U8 SenseKey; /* 0x02 */ + U8 Reserved; /* 0x03 */ +} MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY; + +#define MPI26_MAX_SCSI_SENSE_TRIGGERS (20) +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_3 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 NumSCSISenseTrigger; /* 0x08 */ + U16 Reserved0xA; /* 0x0A */ + MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY SCSISenseTriggers[MPI26_MAX_SCSI_SENSE_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TIGGER_3, Mpi26DriverTriggerPage3_t; + +#define MPI26_DRIVER_TRIGGER_PAGE4_PAGEVERSION (0x01) +typedef struct _MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY { + U16 IOCStatus; /* 0x00 */ + U16 Reserved; /* 0x02 */ + U32 LogInfo; /* 0x04 */ +} MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY; + +#define MPI26_MAX_LOGINFO_TRIGGERS (20) +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_4 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 NumIOCStatusLogInfoTrigger; /* 0x08 */ + U16 Reserved0xA; /* 0x0A */ + MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY IOCStatusLoginfoTriggers[MPI26_MAX_LOGINFO_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TIGGER_4, Mpi26DriverTriggerPage4_t; + +#endif diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 0354898d7cac..71b6a1f834cd 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -2296,7 +2296,6 @@ static int mvumi_cfg_hw_reg(struct mvumi_hba *mhba) break; default: return -1; - break; } return 0; @@ -2559,7 +2558,7 @@ static void mvumi_detach_one(struct pci_dev *pdev) /** * mvumi_shutdown - Shutdown entry point - * @device: Generic device structure + * @pdev: PCI device structure */ static void mvumi_shutdown(struct pci_dev *pdev) { @@ -2568,49 +2567,28 @@ static void mvumi_shutdown(struct pci_dev *pdev) mvumi_flush_cache(mhba); } -static int __maybe_unused mvumi_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused mvumi_suspend(struct device *dev) { - struct mvumi_hba *mhba = NULL; + struct pci_dev *pdev = to_pci_dev(dev); + struct mvumi_hba *mhba = pci_get_drvdata(pdev); - mhba = pci_get_drvdata(pdev); mvumi_flush_cache(mhba); - pci_set_drvdata(pdev, mhba); mhba->instancet->disable_intr(mhba); - free_irq(mhba->pdev->irq, mhba); mvumi_unmap_pci_addr(pdev, mhba->base_addr); - pci_release_regions(pdev); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } -static int __maybe_unused mvumi_resume(struct pci_dev *pdev) +static int __maybe_unused mvumi_resume(struct device *dev) { int ret; - struct mvumi_hba *mhba = NULL; - - mhba = pci_get_drvdata(pdev); - - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "enable device failed\n"); - return ret; - } + struct pci_dev *pdev = to_pci_dev(dev); + struct mvumi_hba *mhba = pci_get_drvdata(pdev); - ret = mvumi_pci_set_master(pdev); ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) goto fail; - ret = pci_request_regions(mhba->pdev, MV_DRIVER_NAME); - if (ret) - goto fail; ret = mvumi_map_pci_addr(mhba->pdev, mhba->base_addr); if (ret) goto release_regions; @@ -2628,12 +2606,6 @@ static int __maybe_unused mvumi_resume(struct pci_dev *pdev) goto unmap_pci_addr; } - ret = request_irq(mhba->pdev->irq, mvumi_isr_handler, IRQF_SHARED, - "mvumi", mhba); - if (ret) { - dev_err(&pdev->dev, "failed to register IRQ\n"); - goto unmap_pci_addr; - } mhba->instancet->enable_intr(mhba); return 0; @@ -2643,11 +2615,12 @@ unmap_pci_addr: release_regions: pci_release_regions(pdev); fail: - pci_disable_device(pdev); return ret; } +static SIMPLE_DEV_PM_OPS(mvumi_pm_ops, mvumi_suspend, mvumi_resume); + static struct pci_driver mvumi_pci_driver = { .name = MV_DRIVER_NAME, @@ -2655,10 +2628,7 @@ static struct pci_driver mvumi_pci_driver = { .probe = mvumi_probe_one, .remove = mvumi_detach_one, .shutdown = mvumi_shutdown, -#ifdef CONFIG_PM - .suspend = mvumi_suspend, - .resume = mvumi_resume, -#endif + .driver.pm = &mvumi_pm_ops, }; module_pci_driver(mvumi_pci_driver); diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c index 5fa0f4ed6565..3d8e91c07dc7 100644 --- a/drivers/scsi/myrb.c +++ b/drivers/scsi/myrb.c @@ -194,7 +194,6 @@ static unsigned short myrb_exec_cmd(struct myrb_hba *cb, cb->qcmd(cb, cmd_blk); spin_unlock_irqrestore(&cb->queue_lock, flags); - WARN_ON(in_interrupt()); wait_for_completion(&cmpl); return cmd_blk->status; } diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c index 7a3ade765ce3..4adf9ded296a 100644 --- a/drivers/scsi/myrs.c +++ b/drivers/scsi/myrs.c @@ -136,7 +136,6 @@ static void myrs_exec_cmd(struct myrs_hba *cs, myrs_qcmd(cs, cmd_blk); spin_unlock_irqrestore(&cs->queue_lock, flags); - WARN_ON(in_interrupt()); wait_for_completion(&complete); } diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index bc5a623519e7..bb3b3884f968 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1102,8 +1102,6 @@ static irqreturn_t nspintr(int irq, void *dev_id) nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); return IRQ_HANDLED; - break; - case PH_RESELECT: //nsp_dbg(NSP_DEBUG_INTR, "phase reselect"); // *sync_neg = SYNC_NOT_YET; diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index 3587f7c8a428..12035baf0997 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -841,10 +841,9 @@ static ssize_t pm8001_store_update_fw(struct device *cdev, pm8001_ha->dev); if (ret) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk( - "Failed to load firmware image file %s, error %d\n", - filename_ptr, ret)); + pm8001_dbg(pm8001_ha, FAIL, + "Failed to load firmware image file %s, error %d\n", + filename_ptr, ret); pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE; goto out; } diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 2b7b2954ec31..c8d4d87c5473 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -400,9 +400,9 @@ int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue) } while ((regVal != shiftValue) && time_before(jiffies, start)); if (regVal != shiftValue) { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("TIMEOUT:SPC_IBW_AXI_TRANSLATION_LOW" - " = 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, + "TIMEOUT:SPC_IBW_AXI_TRANSLATION_LOW = 0x%x\n", + regVal); return -1; } return 0; @@ -416,7 +416,7 @@ int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue) static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit) { - u32 value, offset, i; + u32 offset, i; unsigned long flags; #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000 @@ -467,7 +467,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, so that the written value will be 0x8090c016. This will ensure only down-spreading SSC is enabled on the SPC. *************************************************************/ - value = pm8001_cr32(pm8001_ha, 2, 0xd8); + pm8001_cr32(pm8001_ha, 2, 0xd8); pm8001_cw32(pm8001_ha, 2, 0xd8, 0x8000C016); /*set the shifted destination address to 0x0 to avoid error operation */ @@ -623,12 +623,10 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) value = pm8001_cr32(pm8001_ha, 0, 0x44); offset = value & 0x03FFFFFF; - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Scratchpad 0 Offset: %x\n", offset)); + pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 Offset: %x\n", offset); pcilogic = (value & 0xFC000000) >> 26; pcibar = get_pci_bar_index(pcilogic); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Scratchpad 0 PCI BAR: %d\n", pcibar)); + pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 PCI BAR: %d\n", pcibar); pm8001_ha->main_cfg_tbl_addr = base_addr = pm8001_ha->io_mem[pcibar].memvirtaddr + offset; pm8001_ha->general_stat_tbl_addr = @@ -652,16 +650,15 @@ static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha) * as this is shared with BIOS data */ if (deviceid == 0x8081 || deviceid == 0x0042) { if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - GSM_SM_BASE)); + pm8001_dbg(pm8001_ha, FAIL, + "Shift Bar4 to 0x%x failed\n", + GSM_SM_BASE); return -1; } } /* check the firmware status */ if (-1 == check_fw_ready(pm8001_ha)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Firmware is not ready!\n")); + pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n"); return -EBUSY; } @@ -686,8 +683,7 @@ static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha) } /* notify firmware update finished and check initialization status */ if (0 == mpi_init_check(pm8001_ha)) { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MPI initialize successful!\n")); + pm8001_dbg(pm8001_ha, INIT, "MPI initialize successful!\n"); } else return -EBUSY; /*This register is a 16-bit timer with a resolution of 1us. This is the @@ -709,9 +705,9 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid); if (deviceid == 0x8081 || deviceid == 0x0042) { if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - GSM_SM_BASE)); + pm8001_dbg(pm8001_ha, FAIL, + "Shift Bar4 to 0x%x failed\n", + GSM_SM_BASE); return -1; } } @@ -729,8 +725,8 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) } while ((value != 0) && (--max_wait_count)); if (!max_wait_count) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TIMEOUT:IBDB value/=0x%x\n", value)); + pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:IBDB value/=0x%x\n", + value); return -1; } @@ -747,9 +743,8 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) break; } while (--max_wait_count); if (!max_wait_count) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk(" TIME OUT MPI State = 0x%x\n", - gst_len_mpistate & GST_MPI_STATE_MASK)); + pm8001_dbg(pm8001_ha, FAIL, " TIME OUT MPI State = 0x%x\n", + gst_len_mpistate & GST_MPI_STATE_MASK); return -1; } return 0; @@ -763,25 +758,23 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha) { u32 regVal, regVal1, regVal2; if (mpi_uninit_check(pm8001_ha) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MPI state is not ready\n")); + pm8001_dbg(pm8001_ha, FAIL, "MPI state is not ready\n"); return -1; } /* read the scratch pad 2 register bit 2 */ regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) & SCRATCH_PAD2_FWRDY_RST; if (regVal == SCRATCH_PAD2_FWRDY_RST) { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Firmware is ready for reset .\n")); + pm8001_dbg(pm8001_ha, INIT, "Firmware is ready for reset.\n"); } else { unsigned long flags; /* Trigger NMI twice via RB6 */ spin_lock_irqsave(&pm8001_ha->lock, flags); if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - RB6_ACCESS_REG)); + pm8001_dbg(pm8001_ha, FAIL, + "Shift Bar4 to 0x%x failed\n", + RB6_ACCESS_REG); return -1; } pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET, @@ -794,16 +787,14 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha) if (regVal != SCRATCH_PAD2_FWRDY_RST) { regVal1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); regVal2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TIMEOUT:MSGU_SCRATCH_PAD1" - "=0x%x, MSGU_SCRATCH_PAD2=0x%x\n", - regVal1, regVal2)); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD0 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD3 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3))); + pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:MSGU_SCRATCH_PAD1=0x%x, MSGU_SCRATCH_PAD2=0x%x\n", + regVal1, regVal2); + pm8001_dbg(pm8001_ha, FAIL, + "SCRATCH_PAD0 value = 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0)); + pm8001_dbg(pm8001_ha, FAIL, + "SCRATCH_PAD3 value = 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)); spin_unlock_irqrestore(&pm8001_ha->lock, flags); return -1; } @@ -828,7 +819,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) /* step1: Check FW is ready for soft reset */ if (soft_reset_ready_check(pm8001_ha) != 0) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("FW is not ready\n")); + pm8001_dbg(pm8001_ha, FAIL, "FW is not ready\n"); return -1; } @@ -838,46 +829,43 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) spin_lock_irqsave(&pm8001_ha->lock, flags); if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - MBIC_AAP1_ADDR_BASE)); + pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n", + MBIC_AAP1_ADDR_BASE); return -1; } regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MBIC - NMI Enable VPE0 (IOP)= 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, "MBIC - NMI Enable VPE0 (IOP)= 0x%x\n", + regVal); pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0); /* map 0x70000 to BAR4(0x20), BAR2(win) */ if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - MBIC_IOP_ADDR_BASE)); + pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n", + MBIC_IOP_ADDR_BASE); return -1; } regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MBIC - NMI Enable VPE0 (AAP1)= 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, "MBIC - NMI Enable VPE0 (AAP1)= 0x%x\n", + regVal); pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1, 0x0); regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCIE -Event Interrupt Enable = 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, "PCIE -Event Interrupt Enable = 0x%x\n", + regVal); pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE, 0x0); regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCIE - Event Interrupt = 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, "PCIE - Event Interrupt = 0x%x\n", + regVal); pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT, regVal); regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCIE -Error Interrupt Enable = 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, "PCIE -Error Interrupt Enable = 0x%x\n", + regVal); pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE, 0x0); regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCIE - Error Interrupt = 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, "PCIE - Error Interrupt = 0x%x\n", regVal); pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT, regVal); /* read the scratch pad 1 register bit 2 */ @@ -893,15 +881,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) /* map 0x0700000 to BAR4(0x20), BAR2(win) */ if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - GSM_ADDR_BASE)); + pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n", + GSM_ADDR_BASE); return -1; } - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x0(0x00007b88)-GSM Configuration and" - " Reset = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET))); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x0(0x00007b88)-GSM Configuration and Reset = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET)); /* step 3: host read GSM Configuration and Reset register */ regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET); @@ -916,59 +902,52 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) regVal &= ~(0x00003b00); /* host write GSM Configuration and Reset register */ pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x0 (0x00007b88 ==> 0x00004088) - GSM " - "Configuration and Reset is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET))); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x0 (0x00007b88 ==> 0x00004088) - GSM Configuration and Reset is set to = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET)); /* step 4: */ /* disable GSM - Read Address Parity Check */ regVal1 = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700038 - Read Address Parity Check " - "Enable = 0x%x\n", regVal1)); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x700038 - Read Address Parity Check Enable = 0x%x\n", + regVal1); pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, 0x0); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700038 - Read Address Parity Check Enable" - "is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK))); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x700038 - Read Address Parity Check Enable is set to = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK)); /* disable GSM - Write Address Parity Check */ regVal2 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700040 - Write Address Parity Check" - " Enable = 0x%x\n", regVal2)); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x700040 - Write Address Parity Check Enable = 0x%x\n", + regVal2); pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, 0x0); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700040 - Write Address Parity Check " - "Enable is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK))); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x700040 - Write Address Parity Check Enable is set to = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK)); /* disable GSM - Write Data Parity Check */ regVal3 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x300048 - Write Data Parity Check" - " Enable = 0x%x\n", regVal3)); + pm8001_dbg(pm8001_ha, INIT, "GSM 0x300048 - Write Data Parity Check Enable = 0x%x\n", + regVal3); pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, 0x0); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x300048 - Write Data Parity Check Enable" - "is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK))); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x300048 - Write Data Parity Check Enable is set to = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK)); /* step 5: delay 10 usec */ udelay(10); /* step 5-b: set GPIO-0 output control to tristate anyway */ if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - GPIO_ADDR_BASE)); + pm8001_dbg(pm8001_ha, INIT, "Shift Bar4 to 0x%x failed\n", + GPIO_ADDR_BASE); return -1; } regVal = pm8001_cr32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GPIO Output Control Register:" - " = 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, "GPIO Output Control Register: = 0x%x\n", + regVal); /* set GPIO-0 output control to tri-state */ regVal &= 0xFFFFFFFC; pm8001_cw32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET, regVal); @@ -977,23 +956,20 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) /* map 0x00000 to BAR4(0x20), BAR2(win) */ if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SPC Shift Bar4 to 0x%x failed\n", - SPC_TOP_LEVEL_ADDR_BASE)); + pm8001_dbg(pm8001_ha, FAIL, "SPC Shift Bar4 to 0x%x failed\n", + SPC_TOP_LEVEL_ADDR_BASE); return -1; } regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Top Register before resetting IOP/AAP1" - ":= 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, "Top Register before resetting IOP/AAP1:= 0x%x\n", + regVal); regVal &= ~(SPC_REG_RESET_PCS_IOP_SS | SPC_REG_RESET_PCS_AAP1_SS); pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal); /* step 7: Reset the BDMA/OSSP */ regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Top Register before resetting BDMA/OSSP" - ": = 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, "Top Register before resetting BDMA/OSSP: = 0x%x\n", + regVal); regVal &= ~(SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP); pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal); @@ -1002,9 +978,9 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) /* step 9: bring the BDMA and OSSP out of reset */ regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Top Register before bringing up BDMA/OSSP" - ":= 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, + "Top Register before bringing up BDMA/OSSP:= 0x%x\n", + regVal); regVal |= (SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP); pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal); @@ -1015,14 +991,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) /* map 0x0700000 to BAR4(0x20), BAR2(win) */ if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SPC Shift Bar4 to 0x%x failed\n", - GSM_ADDR_BASE)); + pm8001_dbg(pm8001_ha, FAIL, "SPC Shift Bar4 to 0x%x failed\n", + GSM_ADDR_BASE); return -1; } - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x0 (0x00007b88)-GSM Configuration and " - "Reset = 0x%x\n", pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET))); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x0 (0x00007b88)-GSM Configuration and Reset = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET)); regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET); /* Put those bits to high */ /* GSM XCBI offset = 0x70 0000 @@ -1034,44 +1009,37 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) */ regVal |= (GSM_CONFIG_RESET_VALUE); pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM (0x00004088 ==> 0x00007b88) - GSM" - " Configuration and Reset is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET))); + pm8001_dbg(pm8001_ha, INIT, "GSM (0x00004088 ==> 0x00007b88) - GSM Configuration and Reset is set to = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET)); /* step 12: Restore GSM - Read Address Parity Check */ regVal = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK); /* just for debugging */ - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700038 - Read Address Parity Check Enable" - " = 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x700038 - Read Address Parity Check Enable = 0x%x\n", + regVal); pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, regVal1); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700038 - Read Address Parity" - " Check Enable is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK))); + pm8001_dbg(pm8001_ha, INIT, "GSM 0x700038 - Read Address Parity Check Enable is set to = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK)); /* Restore GSM - Write Address Parity Check */ regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK); pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, regVal2); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700040 - Write Address Parity Check" - " Enable is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK))); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x700040 - Write Address Parity Check Enable is set to = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK)); /* Restore GSM - Write Data Parity Check */ regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK); pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, regVal3); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700048 - Write Data Parity Check Enable" - "is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK))); + pm8001_dbg(pm8001_ha, INIT, + "GSM 0x700048 - Write Data Parity Check Enable is set to = 0x%x\n", + pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK)); /* step 13: bring the IOP and AAP1 out of reset */ /* map 0x00000 to BAR4(0x20), BAR2(win) */ if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - SPC_TOP_LEVEL_ADDR_BASE)); + pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n", + SPC_TOP_LEVEL_ADDR_BASE); return -1; } regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET); @@ -1094,22 +1062,20 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) if (!max_wait_count) { regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TIMEOUT : ToggleVal 0x%x," - "MSGU_SCRATCH_PAD1 = 0x%x\n", - toggleVal, regVal)); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD0 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_0))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD2 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_2))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD3 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_3))); + pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT : ToggleVal 0x%x,MSGU_SCRATCH_PAD1 = 0x%x\n", + toggleVal, regVal); + pm8001_dbg(pm8001_ha, FAIL, + "SCRATCH_PAD0 value = 0x%x\n", + pm8001_cr32(pm8001_ha, 0, + MSGU_SCRATCH_PAD_0)); + pm8001_dbg(pm8001_ha, FAIL, + "SCRATCH_PAD2 value = 0x%x\n", + pm8001_cr32(pm8001_ha, 0, + MSGU_SCRATCH_PAD_2)); + pm8001_dbg(pm8001_ha, FAIL, + "SCRATCH_PAD3 value = 0x%x\n", + pm8001_cr32(pm8001_ha, 0, + MSGU_SCRATCH_PAD_3)); spin_unlock_irqrestore(&pm8001_ha->lock, flags); return -1; } @@ -1124,22 +1090,22 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) if (check_fw_ready(pm8001_ha) == -1) { regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); /* return error if MPI Configuration Table not ready */ - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("FW not ready SCRATCH_PAD1" - " = 0x%x\n", regVal)); + pm8001_dbg(pm8001_ha, INIT, + "FW not ready SCRATCH_PAD1 = 0x%x\n", + regVal); regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2); /* return error if MPI Configuration Table not ready */ - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("FW not ready SCRATCH_PAD2" - " = 0x%x\n", regVal)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD0 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_0))); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD3 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_3))); + pm8001_dbg(pm8001_ha, INIT, + "FW not ready SCRATCH_PAD2 = 0x%x\n", + regVal); + pm8001_dbg(pm8001_ha, INIT, + "SCRATCH_PAD0 value = 0x%x\n", + pm8001_cr32(pm8001_ha, 0, + MSGU_SCRATCH_PAD_0)); + pm8001_dbg(pm8001_ha, INIT, + "SCRATCH_PAD3 value = 0x%x\n", + pm8001_cr32(pm8001_ha, 0, + MSGU_SCRATCH_PAD_3)); spin_unlock_irqrestore(&pm8001_ha->lock, flags); return -1; } @@ -1147,8 +1113,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) pm8001_bar4_shift(pm8001_ha, 0); spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SPC soft reset Complete\n")); + pm8001_dbg(pm8001_ha, INIT, "SPC soft reset Complete\n"); return 0; } @@ -1156,8 +1121,7 @@ static void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) { u32 i; u32 regVal; - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("chip reset start\n")); + pm8001_dbg(pm8001_ha, INIT, "chip reset start\n"); /* do SPC chip reset. */ regVal = pm8001_cr32(pm8001_ha, 1, SPC_REG_RESET); @@ -1181,8 +1145,7 @@ static void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) mdelay(1); } while ((--i) != 0); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("chip reset finished\n")); + pm8001_dbg(pm8001_ha, INIT, "chip reset finished\n"); } /** @@ -1356,12 +1319,18 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, { u32 Header = 0, hpriority = 0, bc = 1, category = 0x02; void *pMessage; - - if (pm8001_mpi_msg_free_get(circularQ, pm8001_ha->iomb_size, - &pMessage) < 0) { - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("No free mpi buffer\n")); - return -ENOMEM; + unsigned long flags; + int q_index = circularQ - pm8001_ha->inbnd_q_tbl; + int rv = -1; + + WARN_ON(q_index >= PM8001_MAX_INB_NUM); + spin_lock_irqsave(&circularQ->iq_lock, flags); + rv = pm8001_mpi_msg_free_get(circularQ, pm8001_ha->iomb_size, + &pMessage); + if (rv < 0) { + pm8001_dbg(pm8001_ha, IO, "No free mpi buffer\n"); + rv = -ENOMEM; + goto done; } if (nb > (pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr))) @@ -1380,11 +1349,13 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, /*Update the PI to the firmware*/ pm8001_cw32(pm8001_ha, circularQ->pi_pci_bar, circularQ->pi_offset, circularQ->producer_idx); - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("INB Q %x OPCODE:%x , UPDATED PI=%d CI=%d\n", - responseQueue, opCode, circularQ->producer_idx, - circularQ->consumer_index)); - return 0; + pm8001_dbg(pm8001_ha, DEVIO, + "INB Q %x OPCODE:%x , UPDATED PI=%d CI=%d\n", + responseQueue, opCode, circularQ->producer_idx, + circularQ->consumer_index); +done: + spin_unlock_irqrestore(&circularQ->iq_lock, flags); + return rv; } u32 pm8001_mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg, @@ -1398,17 +1369,17 @@ u32 pm8001_mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg, pOutBoundMsgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt + circularQ->consumer_idx * pm8001_ha->iomb_size); if (pOutBoundMsgHeader != msgHeader) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("consumer_idx = %d msgHeader = %p\n", - circularQ->consumer_idx, msgHeader)); + pm8001_dbg(pm8001_ha, FAIL, + "consumer_idx = %d msgHeader = %p\n", + circularQ->consumer_idx, msgHeader); /* Update the producer index from SPC */ producer_index = pm8001_read_32(circularQ->pi_virt); circularQ->producer_index = cpu_to_le32(producer_index); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("consumer_idx = %d producer_index = %d" - "msgHeader = %p\n", circularQ->consumer_idx, - circularQ->producer_index, msgHeader)); + pm8001_dbg(pm8001_ha, FAIL, + "consumer_idx = %d producer_index = %dmsgHeader = %p\n", + circularQ->consumer_idx, + circularQ->producer_index, msgHeader); return 0; } /* free the circular queue buffer elements associated with the message*/ @@ -1420,9 +1391,8 @@ u32 pm8001_mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg, /* Update the producer index from SPC*/ producer_index = pm8001_read_32(circularQ->pi_virt); circularQ->producer_index = cpu_to_le32(producer_index); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk(" CI=%d PI=%d\n", circularQ->consumer_idx, - circularQ->producer_index)); + pm8001_dbg(pm8001_ha, IO, " CI=%d PI=%d\n", + circularQ->consumer_idx, circularQ->producer_index); return 0; } @@ -1452,10 +1422,10 @@ u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, /* read header */ header_tmp = pm8001_read_32(msgHeader); msgHeader_tmp = cpu_to_le32(header_tmp); - PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( - "outbound opcode msgheader:%x ci=%d pi=%d\n", - msgHeader_tmp, circularQ->consumer_idx, - circularQ->producer_index)); + pm8001_dbg(pm8001_ha, DEVIO, + "outbound opcode msgheader:%x ci=%d pi=%d\n", + msgHeader_tmp, circularQ->consumer_idx, + circularQ->producer_index); if (0 != (le32_to_cpu(msgHeader_tmp) & 0x80000000)) { if (OPC_OUB_SKIP_ENTRY != (le32_to_cpu(msgHeader_tmp) & 0xfff)) { @@ -1464,12 +1434,11 @@ u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, sizeof(struct mpi_msg_hdr); *pBC = (u8)((le32_to_cpu(msgHeader_tmp) >> 24) & 0x1f); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk(": CI=%d PI=%d " - "msgHeader=%x\n", - circularQ->consumer_idx, - circularQ->producer_index, - msgHeader_tmp)); + pm8001_dbg(pm8001_ha, IO, + ": CI=%d PI=%d msgHeader=%x\n", + circularQ->consumer_idx, + circularQ->producer_index, + msgHeader_tmp); return MPI_IO_STATUS_SUCCESS; } else { circularQ->consumer_idx = @@ -1578,17 +1547,15 @@ void pm8001_work_fn(struct work_struct *work) ts->stat = SAS_QUEUE_FULL; pm8001_dev = ccb->device; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); spin_lock_irqsave(&t->task_state_lock, flags1); t->task_state_flags &= ~SAS_TASK_STATE_PENDING; t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags1); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p" - " done with event 0x%x resp 0x%x stat 0x%x but" - " aborted by upper layer!\n", - t, pw->handler, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with event 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, pw->handler, ts->resp, ts->stat); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); spin_unlock_irqrestore(&pm8001_ha->lock, flags); } else { @@ -1608,26 +1575,16 @@ void pm8001_work_fn(struct work_struct *work) unsigned long flags, flags1; int i, ret = 0; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); ret = pm8001_query_task(t); - PM8001_IO_DBG(pm8001_ha, - switch (ret) { - case TMF_RESP_FUNC_SUCC: - pm8001_printk("...Task on lu\n"); - break; - - case TMF_RESP_FUNC_COMPLETE: - pm8001_printk("...Task NOT on lu\n"); - break; - - default: - PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( - "...query task failed!!!\n")); - break; - }); + if (ret == TMF_RESP_FUNC_SUCC) + pm8001_dbg(pm8001_ha, IO, "...Task on lu\n"); + else if (ret == TMF_RESP_FUNC_COMPLETE) + pm8001_dbg(pm8001_ha, IO, "...Task NOT on lu\n"); + else + pm8001_dbg(pm8001_ha, DEVIO, "...query task failed!!!\n"); spin_lock_irqsave(&pm8001_ha->lock, flags); @@ -1672,8 +1629,7 @@ void pm8001_work_fn(struct work_struct *work) break; default: /* device misbehavior */ ret = TMF_RESP_FUNC_FAILED; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("...Reset phy\n")); + pm8001_dbg(pm8001_ha, IO, "...Reset phy\n"); pm8001_I_T_nexus_reset(dev); break; } @@ -1687,15 +1643,14 @@ void pm8001_work_fn(struct work_struct *work) default: /* device misbehavior */ spin_unlock_irqrestore(&pm8001_ha->lock, flags); ret = TMF_RESP_FUNC_FAILED; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("...Reset phy\n")); + pm8001_dbg(pm8001_ha, IO, "...Reset phy\n"); pm8001_I_T_nexus_reset(dev); } if (ret == TMF_RESP_FUNC_FAILED) t = NULL; pm8001_open_reject_retry(pm8001_ha, t, pm8001_dev); - PM8001_IO_DBG(pm8001_ha, pm8001_printk("...Complete\n")); + pm8001_dbg(pm8001_ha, IO, "...Complete\n"); } break; case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: dev = pm8001_dev->sas_device; @@ -1749,15 +1704,14 @@ static void pm8001_send_abort_all(struct pm8001_hba_info *pm8001_ha, int ret; if (!pm8001_ha_dev) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("dev is null\n")); + pm8001_dbg(pm8001_ha, FAIL, "dev is null\n"); return; } task = sas_alloc_slow_task(GFP_ATOMIC); if (!task) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("cannot " - "allocate task\n")); + pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task\n"); return; } @@ -1802,8 +1756,7 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha, task = sas_alloc_slow_task(GFP_ATOMIC); if (!task) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("cannot allocate task !!!\n")); + pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task !!!\n"); return; } task->task_done = pm8001_task_done; @@ -1811,8 +1764,7 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha, res = pm8001_tag_alloc(pm8001_ha, &ccb_tag); if (res) { sas_free_task(task); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("cannot allocate tag !!!\n")); + pm8001_dbg(pm8001_ha, FAIL, "cannot allocate tag !!!\n"); return; } @@ -1823,8 +1775,8 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha, if (!dev) { sas_free_task(task); pm8001_tag_free(pm8001_ha, ccb_tag); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Domain device cannot be allocated\n")); + pm8001_dbg(pm8001_ha, FAIL, + "Domain device cannot be allocated\n"); return; } task->dev = dev; @@ -1901,27 +1853,25 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) t = ccb->task; if (status && status != IO_UNDERFLOW) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("sas IO status 0x%x\n", status)); + pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", status); if (unlikely(!t || !t->lldd_task || !t->dev)) return; ts = &t->task_status; /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SAS Address of IO Failure Drive:" - "%016llx", SAS_ADDR(t->dev->sas_addr))); + pm8001_dbg(pm8001_ha, FAIL, "SAS Address of IO Failure Drive:%016llx\n", + SAS_ADDR(t->dev->sas_addr)); if (status) - PM8001_IOERR_DBG(pm8001_ha, pm8001_printk( - "status:0x%x, tag:0x%x, task:0x%p\n", - status, tag, t)); + pm8001_dbg(pm8001_ha, IOERR, + "status:0x%x, tag:0x%x, task:0x%p\n", + status, tag, t); switch (status) { case IO_SUCCESS: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS" - ",param = %d\n", param)); + pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS,param = %d\n", + param); if (param == 0) { ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_GOOD; @@ -1933,69 +1883,63 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) sas_ssp_task_response(pm8001_ha->dev, t, iu); } if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ABORTED IOMB Tag\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_ABORTED_TASK; break; case IO_UNDERFLOW: /* SSP Completion with error */ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW" - ",param = %d\n", param)); + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW,param = %d\n", + param); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_UNDERRUN; ts->residual = param; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_NO_DEVICE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_NO_DEVICE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; /* Force the midlayer to retry */ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_EPROTO; break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; @@ -2005,68 +1949,59 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; break; case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_XFER_ERROR_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; break; case IO_XFER_ERROR_DMA: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_DMA\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_XFER_ERROR_OFFSET_MISMATCH: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; break; case IO_PORT_IN_RESET: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_PORT_IN_RESET\n")); + pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; break; case IO_DS_NON_OPERATIONAL: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_NON_OPERATIONAL\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; if (!t->uldd_task) @@ -2075,51 +2010,44 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) IO_DS_NON_OPERATIONAL); break; case IO_DS_IN_RECOVERY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_RECOVERY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; break; case IO_TM_TAG_NOT_FOUND: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_TM_TAG_NOT_FOUND\n")); + pm8001_dbg(pm8001_ha, IO, "IO_TM_TAG_NOT_FOUND\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; break; case IO_SSP_EXT_IU_ZERO_LEN_ERROR: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_SSP_EXT_IU_ZERO_LEN_ERROR\n")); + pm8001_dbg(pm8001_ha, IO, "IO_SSP_EXT_IU_ZERO_LEN_ERROR\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; break; case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", status)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; break; } - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("scsi_status = %x\n ", - psspPayload->ssp_resp_iu.status)); + pm8001_dbg(pm8001_ha, IO, "scsi_status = %x\n", + psspPayload->ssp_resp_iu.status); spin_lock_irqsave(&t->task_state_lock, flags); t->task_state_flags &= ~SAS_TASK_STATE_PENDING; t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p done with" - " io_status 0x%x resp 0x%x " - "stat 0x%x but aborted by upper layer!\n", - t, status, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, status, ts->resp, ts->stat); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); @@ -2148,60 +2076,52 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) t = ccb->task; pm8001_dev = ccb->device; if (event) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("sas IO status 0x%x\n", event)); + pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", event); if (unlikely(!t || !t->lldd_task || !t->dev)) return; ts = &t->task_status; - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("port_id = %x,device_id = %x\n", - port_id, dev_id)); + pm8001_dbg(pm8001_ha, DEVIO, "port_id = %x,device_id = %x\n", + port_id, dev_id); switch (event) { case IO_OVERFLOW: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n");) + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; ts->residual = 0; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK); return; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT" - "_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_EPROTO; break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; @@ -2211,88 +2131,78 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; break; case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_XFER_ERROR_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT); return; case IO_XFER_ERROR_UNEXPECTED_PHASE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_XFER_RDY_OVERRUN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_OVERRUN\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_OFFSET_MISMATCH: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_CMD_FRAME_ISSUED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk(" IO_XFER_CMD_FRAME_ISSUED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n"); return; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", event)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", event); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; @@ -2304,10 +2214,8 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p done with" - " event 0x%x resp 0x%x " - "stat 0x%x but aborted by upper layer!\n", - t, event, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with event 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, event, ts->resp, ts->stat); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); @@ -2343,8 +2251,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) tag = le32_to_cpu(psataPayload->tag); if (!tag) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("tag null\n")); + pm8001_dbg(pm8001_ha, FAIL, "tag null\n"); return; } ccb = &pm8001_ha->ccb_info[tag]; @@ -2353,8 +2260,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) t = ccb->task; pm8001_dev = ccb->device; } else { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("ccb null\n")); + pm8001_dbg(pm8001_ha, FAIL, "ccb null\n"); return; } @@ -2362,29 +2268,26 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) if (t->dev && (t->dev->lldd_dev)) pm8001_dev = t->dev->lldd_dev; } else { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task null\n")); + pm8001_dbg(pm8001_ha, FAIL, "task null\n"); return; } if ((pm8001_dev && !(pm8001_dev->id & NCQ_READ_LOG_FLAG)) && unlikely(!t || !t->lldd_task || !t->dev)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task or dev null\n")); + pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n"); return; } ts = &t->task_status; if (!ts) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("ts null\n")); + pm8001_dbg(pm8001_ha, FAIL, "ts null\n"); return; } if (status) - PM8001_IOERR_DBG(pm8001_ha, pm8001_printk( - "status:0x%x, tag:0x%x, task::0x%p\n", - status, tag, t)); + pm8001_dbg(pm8001_ha, IOERR, + "status:0x%x, tag:0x%x, task::0x%p\n", + status, tag, t); /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && @@ -2416,19 +2319,19 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) & 0xff000000)) + pm8001_dev->attached_phy + 0x10); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SAS Address of IO Failure Drive:" - "%08x%08x", temp_sata_addr_hi, - temp_sata_addr_low)); + pm8001_dbg(pm8001_ha, FAIL, + "SAS Address of IO Failure Drive:%08x%08x\n", + temp_sata_addr_hi, + temp_sata_addr_low); } else { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SAS Address of IO Failure Drive:" - "%016llx", SAS_ADDR(t->dev->sas_addr))); + pm8001_dbg(pm8001_ha, FAIL, + "SAS Address of IO Failure Drive:%016llx\n", + SAS_ADDR(t->dev->sas_addr)); } } switch (status) { case IO_SUCCESS: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n"); if (param == 0) { ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_GOOD; @@ -2450,99 +2353,102 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_PROTO_RESPONSE; ts->residual = param; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("SAS_PROTO_RESPONSE len = %d\n", - param)); + pm8001_dbg(pm8001_ha, IO, + "SAS_PROTO_RESPONSE len = %d\n", + param); sata_resp = &psataPayload->sata_resp[0]; resp = (struct ata_task_resp *)ts->buf; if (t->ata_task.dma_xfer == 0 && t->data_dir == DMA_FROM_DEVICE) { len = sizeof(struct pio_setup_fis); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("PIO read len = %d\n", len)); + pm8001_dbg(pm8001_ha, IO, + "PIO read len = %d\n", len); } else if (t->ata_task.use_ncq) { len = sizeof(struct set_dev_bits_fis); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("FPDMA len = %d\n", len)); + pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n", + len); } else { len = sizeof(struct dev_to_host_fis); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("other len = %d\n", len)); + pm8001_dbg(pm8001_ha, IO, "other len = %d\n", + len); } if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { resp->frame_len = len; memcpy(&resp->ending_fis[0], sata_resp, len); ts->buf_valid_size = sizeof(*resp); } else - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("response to large\n")); + pm8001_dbg(pm8001_ha, IO, + "response too large\n"); } if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ABORTED IOMB Tag\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_ABORTED_TASK; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; /* following cases are to do cases */ case IO_UNDERFLOW: /* SATA Completion with error */ - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_UNDERFLOW param = %d\n", param)); + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW param = %d\n", param); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_UNDERRUN; ts->residual = param; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_NO_DEVICE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_NO_DEVICE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_INTERRUPTED; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT" - "_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_EPROTO; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2556,8 +2462,8 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; @@ -2572,17 +2478,15 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_STP_RESOURCES" - "_BUSY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2596,57 +2500,65 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_DMA: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_DMA\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_ABORTED_TASK; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_SATA_LINK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_SATA_LINK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_SATA_LINK_TIMEOUT\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_DEV_NO_RESPONSE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_REJECTED_NCQ_MODE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_REJECTED_NCQ_MODE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_UNDERRUN; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_PORT_IN_RESET: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_PORT_IN_RESET\n")); + pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_DS_NON_OPERATIONAL: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_NON_OPERATIONAL\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2659,14 +2571,14 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_DS_IN_RECOVERY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk(" IO_DS_IN_RECOVERY\n")); + pm8001_dbg(pm8001_ha, IO, " IO_DS_IN_RECOVERY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_DS_IN_ERROR: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_ERROR\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_ERROR\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2679,18 +2591,21 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", status)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; } spin_lock_irqsave(&t->task_state_lock, flags); @@ -2699,10 +2614,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task 0x%p done with io_status 0x%x" - " resp 0x%x stat 0x%x but aborted by upper layer!\n", - t, status, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, + "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, status, ts->resp, ts->stat); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); @@ -2731,12 +2645,10 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) t = ccb->task; pm8001_dev = ccb->device; } else { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("No CCB !!!. returning\n")); + pm8001_dbg(pm8001_ha, FAIL, "No CCB !!!. returning\n"); } if (event) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SATA EVENT 0x%x\n", event)); + pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event); /* Check if this is NCQ error */ if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) { @@ -2752,61 +2664,54 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) t = ccb->task; pm8001_dev = ccb->device; if (event) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("sata IO status 0x%x\n", event)); + pm8001_dbg(pm8001_ha, FAIL, "sata IO status 0x%x\n", event); if (unlikely(!t || !t->lldd_task || !t->dev)) return; ts = &t->task_status; - PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( - "port_id:0x%x, device_id:0x%x, tag:0x%x, event:0x%x\n", - port_id, dev_id, tag, event)); + pm8001_dbg(pm8001_ha, DEVIO, + "port_id:0x%x, device_id:0x%x, tag:0x%x, event:0x%x\n", + port_id, dev_id, tag, event); switch (event) { case IO_OVERFLOW: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n")); + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; ts->residual = 0; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_INTERRUPTED; break; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT" - "_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_EPROTO; break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; break; case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2820,94 +2725,82 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) } break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; break; case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; break; case IO_XFER_ERROR_PEER_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PEER_ABORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PEER_ABORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; break; case IO_XFER_ERROR_REJECTED_NCQ_MODE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_REJECTED_NCQ_MODE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_UNDERRUN; break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_UNEXPECTED_PHASE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_XFER_RDY_OVERRUN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_OVERRUN\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_OFFSET_MISMATCH: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_CMD_FRAME_ISSUED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_CMD_FRAME_ISSUED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n"); break; case IO_XFER_PIO_SETUP_ERROR: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_PIO_SETUP_ERROR\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_PIO_SETUP_ERROR\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", event)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", event); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; @@ -2919,10 +2812,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task 0x%p done with io_status 0x%x" - " resp 0x%x stat 0x%x but aborted by upper layer!\n", - t, event, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, + "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, event, ts->resp, ts->stat); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); @@ -2952,86 +2844,79 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts = &t->task_status; pm8001_dev = ccb->device; if (status) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("smp IO status 0x%x\n", status)); - PM8001_IOERR_DBG(pm8001_ha, - pm8001_printk("status:0x%x, tag:0x%x, task:0x%p\n", - status, tag, t)); + pm8001_dbg(pm8001_ha, FAIL, "smp IO status 0x%x\n", status); + pm8001_dbg(pm8001_ha, IOERR, + "status:0x%x, tag:0x%x, task:0x%p\n", + status, tag, t); } if (unlikely(!t || !t->lldd_task || !t->dev)) return; switch (status) { case IO_SUCCESS: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_GOOD; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ABORTED IOMB\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_ABORTED_TASK; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_OVERFLOW: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n")); + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; ts->residual = 0; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_NO_DEVICE: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_NO_DEVICE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_PHY_DOWN; break; case IO_ERROR_HW_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ERROR_HW_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ERROR_HW_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_BUSY; break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_BUSY; break; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_BUSY; break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; break; case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; @@ -3040,76 +2925,67 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; break; case IO_XFER_ERROR_RX_FRAME: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_RX_FRAME\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_RX_FRAME\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_ERROR_INTERNAL_SMP_RESOURCE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ERROR_INTERNAL_SMP_RESOURCE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ERROR_INTERNAL_SMP_RESOURCE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_QUEUE_FULL; break; case IO_PORT_IN_RESET: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_PORT_IN_RESET\n")); + pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_DS_NON_OPERATIONAL: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_NON_OPERATIONAL\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; break; case IO_DS_IN_RECOVERY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_RECOVERY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", status)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; /* not allowed case. Therefore, return failed status */ @@ -3121,10 +2997,8 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p done with" - " io_status 0x%x resp 0x%x " - "stat 0x%x but aborted by upper layer!\n", - t, status, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, status, ts->resp, ts->stat); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); @@ -3146,9 +3020,8 @@ void pm8001_mpi_set_dev_state_resp(struct pm8001_hba_info *pm8001_ha, u32 device_id = le32_to_cpu(pPayload->device_id); u8 pds = le32_to_cpu(pPayload->pds_nds) & PDS_BITS; u8 nds = le32_to_cpu(pPayload->pds_nds) & NDS_BITS; - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Set device id = 0x%x state " - "from 0x%x to 0x%x status = 0x%x!\n", - device_id, pds, nds, status)); + pm8001_dbg(pm8001_ha, MSG, "Set device id = 0x%x state from 0x%x to 0x%x status = 0x%x!\n", + device_id, pds, nds, status); complete(pm8001_dev->setds_completion); ccb->task = NULL; ccb->ccb_tag = 0xFFFFFFFF; @@ -3163,10 +3036,9 @@ void pm8001_mpi_set_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag]; u32 dlen_status = le32_to_cpu(pPayload->dlen_status); complete(pm8001_ha->nvmd_completion); - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Set nvm data complete!\n")); + pm8001_dbg(pm8001_ha, MSG, "Set nvm data complete!\n"); if ((dlen_status & NVMD_STAT) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Set nvm data error!\n")); + pm8001_dbg(pm8001_ha, FAIL, "Set nvm data error!\n"); return; } ccb->task = NULL; @@ -3188,26 +3060,22 @@ pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) void *virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr; fw_control_context = ccb->fw_control_context; - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Get nvm data complete!\n")); + pm8001_dbg(pm8001_ha, MSG, "Get nvm data complete!\n"); if ((dlen_status & NVMD_STAT) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Get nvm data error!\n")); + pm8001_dbg(pm8001_ha, FAIL, "Get nvm data error!\n"); complete(pm8001_ha->nvmd_completion); return; } if (ir_tds_bn_dps_das_nvm & IPMode) { /* indirect mode - IR bit set */ - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Get NVMD success, IR=1\n")); + pm8001_dbg(pm8001_ha, MSG, "Get NVMD success, IR=1\n"); if ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == TWI_DEVICE) { if (ir_tds_bn_dps_das_nvm == 0x80a80200) { memcpy(pm8001_ha->sas_addr, ((u8 *)virt_addr + 4), SAS_ADDR_SIZE); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Get SAS address" - " from VPD successfully!\n")); + pm8001_dbg(pm8001_ha, MSG, "Get SAS address from VPD successfully!\n"); } } else if (((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == C_SEEPROM) || ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == VPD_FLASH) || @@ -3218,14 +3086,14 @@ pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) ; } else { /* Should not be happened*/ - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("(IR=1)Wrong Device type 0x%x\n", - ir_tds_bn_dps_das_nvm)); + pm8001_dbg(pm8001_ha, MSG, + "(IR=1)Wrong Device type 0x%x\n", + ir_tds_bn_dps_das_nvm); } } else /* direct mode */{ - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Get NVMD success, IR=0, dataLen=%d\n", - (dlen_status & NVMD_LEN) >> 24)); + pm8001_dbg(pm8001_ha, MSG, + "Get NVMD success, IR=0, dataLen=%d\n", + (dlen_status & NVMD_LEN) >> 24); } /* Though fw_control_context is freed below, usrAddr still needs * to be updated as this holds the response to the request function @@ -3234,10 +3102,15 @@ pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_ha->memoryMap.region[NVMD].virt_ptr, fw_control_context->len); kfree(ccb->fw_control_context); + /* To avoid race condition, complete should be + * called after the message is copied to + * fw_control_context->usrAddr + */ + complete(pm8001_ha->nvmd_completion); + pm8001_dbg(pm8001_ha, MSG, "Set nvm data complete!\n"); ccb->task = NULL; ccb->ccb_tag = 0xFFFFFFFF; pm8001_tag_free(pm8001_ha, tag); - complete(pm8001_ha->nvmd_completion); } int pm8001_mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb) @@ -3250,13 +3123,13 @@ int pm8001_mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb) u32 phy_op = le32_to_cpu(pPayload->phyop_phyid) & OP_BITS; tag = le32_to_cpu(pPayload->tag); if (status != 0) { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("%x phy execute %x phy op failed!\n", - phy_id, phy_op)); + pm8001_dbg(pm8001_ha, MSG, + "%x phy execute %x phy op failed!\n", + phy_id, phy_op); } else { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("%x phy execute %x phy op success!\n", - phy_id, phy_op)); + pm8001_dbg(pm8001_ha, MSG, + "%x phy execute %x phy op success!\n", + phy_id, phy_op); pm8001_ha->phy[phy_id].reset_success = true; } if (pm8001_ha->phy[phy_id].enable_completion) { @@ -3303,7 +3176,7 @@ void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i) } else if (phy->phy_type & PORT_TYPE_SATA) { /*Nothing*/ } - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("phy %d byte dmaded.\n", i)); + pm8001_dbg(pm8001_ha, MSG, "phy %d byte dmaded.\n", i); sas_phy->frame_rcvd_size = phy->frame_rcvd_size; pm8001_ha->sas->notify_port_event(sas_phy, PORTE_BYTES_DMAED); @@ -3426,37 +3299,34 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) u8 deviceType = pPayload->sas_identify.dev_type; port->port_state = portstate; phy->phy_state = PHY_STATE_LINK_UP_SPC; - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SAS_PHY_UP port id = %d, phy id = %d\n", - port_id, phy_id)); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_SAS_PHY_UP port id = %d, phy id = %d\n", + port_id, phy_id); switch (deviceType) { case SAS_PHY_UNUSED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("device type no device.\n")); + pm8001_dbg(pm8001_ha, MSG, "device type no device.\n"); break; case SAS_END_DEVICE: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n")); + pm8001_dbg(pm8001_ha, MSG, "end device.\n"); pm8001_chip_phy_ctl_req(pm8001_ha, phy_id, PHY_NOTIFY_ENABLE_SPINUP); port->port_attached = 1; pm8001_get_lrate_mode(phy, link_rate); break; case SAS_EDGE_EXPANDER_DEVICE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("expander device.\n")); + pm8001_dbg(pm8001_ha, MSG, "expander device.\n"); port->port_attached = 1; pm8001_get_lrate_mode(phy, link_rate); break; case SAS_FANOUT_EXPANDER_DEVICE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("fanout expander device.\n")); + pm8001_dbg(pm8001_ha, MSG, "fanout expander device.\n"); port->port_attached = 1; pm8001_get_lrate_mode(phy, link_rate); break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("unknown device type(%x)\n", deviceType)); + pm8001_dbg(pm8001_ha, DEVIO, "unknown device type(%x)\n", + deviceType); break; } phy->phy_type |= PORT_TYPE_SAS; @@ -3502,9 +3372,8 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) struct sas_ha_struct *sas_ha = pm8001_ha->sas; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; unsigned long flags; - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SATA_PHY_UP port id = %d," - " phy id = %d\n", port_id, phy_id)); + pm8001_dbg(pm8001_ha, DEVIO, "HW_EVENT_SATA_PHY_UP port id = %d, phy id = %d\n", + port_id, phy_id); port->port_state = portstate; phy->phy_state = PHY_STATE_LINK_UP_SPC; port->port_attached = 1; @@ -3552,37 +3421,35 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) case PORT_VALID: break; case PORT_INVALID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" PortInvalid portID %d\n", port_id)); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Last phy Down and port invalid\n")); + pm8001_dbg(pm8001_ha, MSG, " PortInvalid portID %d\n", + port_id); + pm8001_dbg(pm8001_ha, MSG, + " Last phy Down and port invalid\n"); port->port_attached = 0; pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, port_id, phy_id, 0, 0); break; case PORT_IN_RESET: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Port In Reset portID %d\n", port_id)); + pm8001_dbg(pm8001_ha, MSG, " Port In Reset portID %d\n", + port_id); break; case PORT_NOT_ESTABLISHED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and PORT_NOT_ESTABLISHED\n")); + pm8001_dbg(pm8001_ha, MSG, + " phy Down and PORT_NOT_ESTABLISHED\n"); port->port_attached = 0; break; case PORT_LOSTCOMM: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and PORT_LOSTCOMM\n")); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Last phy Down and port invalid\n")); + pm8001_dbg(pm8001_ha, MSG, " phy Down and PORT_LOSTCOMM\n"); + pm8001_dbg(pm8001_ha, MSG, + " Last phy Down and port invalid\n"); port->port_attached = 0; pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, port_id, phy_id, 0, 0); break; default: port->port_attached = 0; - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk(" phy Down and(default) = %x\n", - portstate)); + pm8001_dbg(pm8001_ha, DEVIO, " phy Down and(default) = %x\n", + portstate); break; } @@ -3613,44 +3480,42 @@ int pm8001_mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_dev = ccb->device; status = le32_to_cpu(registerRespPayload->status); device_id = le32_to_cpu(registerRespPayload->device_id); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" register device is status = %d\n", status)); + pm8001_dbg(pm8001_ha, MSG, " register device is status = %d\n", + status); switch (status) { case DEVREG_SUCCESS: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("DEVREG_SUCCESS\n")); + pm8001_dbg(pm8001_ha, MSG, "DEVREG_SUCCESS\n"); pm8001_dev->device_id = device_id; break; case DEVREG_FAILURE_OUT_OF_RESOURCE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_OUT_OF_RESOURCE\n")); + pm8001_dbg(pm8001_ha, MSG, "DEVREG_FAILURE_OUT_OF_RESOURCE\n"); break; case DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED\n")); + pm8001_dbg(pm8001_ha, MSG, + "DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED\n"); break; case DEVREG_FAILURE_INVALID_PHY_ID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_INVALID_PHY_ID\n")); + pm8001_dbg(pm8001_ha, MSG, "DEVREG_FAILURE_INVALID_PHY_ID\n"); break; case DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED\n")); + pm8001_dbg(pm8001_ha, MSG, + "DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED\n"); break; case DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE\n")); + pm8001_dbg(pm8001_ha, MSG, + "DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE\n"); break; case DEVREG_FAILURE_PORT_NOT_VALID_STATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_PORT_NOT_VALID_STATE\n")); + pm8001_dbg(pm8001_ha, MSG, + "DEVREG_FAILURE_PORT_NOT_VALID_STATE\n"); break; case DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID\n")); + pm8001_dbg(pm8001_ha, MSG, + "DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID\n"); break; default: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_DEVICE_TYPE_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, MSG, + "DEVREG_FAILURE_DEVICE_TYPE_NOT_SUPPORTED\n"); break; } complete(pm8001_dev->dcompletion); @@ -3670,9 +3535,9 @@ int pm8001_mpi_dereg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) status = le32_to_cpu(registerRespPayload->status); device_id = le32_to_cpu(registerRespPayload->device_id); if (status != 0) - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" deregister device failed ,status = %x" - ", device_id = %x\n", status, device_id)); + pm8001_dbg(pm8001_ha, MSG, + " deregister device failed ,status = %x, device_id = %x\n", + status, device_id); return 0; } @@ -3692,44 +3557,37 @@ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, status = le32_to_cpu(ppayload->status); switch (status) { case FLASH_UPDATE_COMPLETE_PENDING_REBOOT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_COMPLETE_PENDING_REBOOT\n")); + pm8001_dbg(pm8001_ha, MSG, + ": FLASH_UPDATE_COMPLETE_PENDING_REBOOT\n"); break; case FLASH_UPDATE_IN_PROGRESS: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_IN_PROGRESS\n")); + pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_IN_PROGRESS\n"); break; case FLASH_UPDATE_HDR_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_HDR_ERR\n")); + pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_HDR_ERR\n"); break; case FLASH_UPDATE_OFFSET_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_OFFSET_ERR\n")); + pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_OFFSET_ERR\n"); break; case FLASH_UPDATE_CRC_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_CRC_ERR\n")); + pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_CRC_ERR\n"); break; case FLASH_UPDATE_LENGTH_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_LENGTH_ERR\n")); + pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_LENGTH_ERR\n"); break; case FLASH_UPDATE_HW_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_HW_ERR\n")); + pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_HW_ERR\n"); break; case FLASH_UPDATE_DNLD_NOT_SUPPORTED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_DNLD_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, MSG, + ": FLASH_UPDATE_DNLD_NOT_SUPPORTED\n"); break; case FLASH_UPDATE_DISABLED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_DISABLED\n")); + pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_DISABLED\n"); break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("No matched status = %d\n", status)); + pm8001_dbg(pm8001_ha, DEVIO, "No matched status = %d\n", + status); break; } kfree(ccb->fw_control_context); @@ -3747,12 +3605,11 @@ int pm8001_mpi_general_event(struct pm8001_hba_info *pm8001_ha , void *piomb) struct general_event_resp *pPayload = (struct general_event_resp *)(piomb + 4); status = le32_to_cpu(pPayload->status); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" status = 0x%x\n", status)); + pm8001_dbg(pm8001_ha, MSG, " status = 0x%x\n", status); for (i = 0; i < GENERAL_EVENT_PAYLOAD; i++) - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("inb_IOMB_payload[0x%x] 0x%x,\n", i, - pPayload->inb_IOMB_payload[i])); + pm8001_dbg(pm8001_ha, MSG, "inb_IOMB_payload[0x%x] 0x%x,\n", + i, + pPayload->inb_IOMB_payload[i]); return 0; } @@ -3772,8 +3629,7 @@ int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) status = le32_to_cpu(pPayload->status); tag = le32_to_cpu(pPayload->tag); if (!tag) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk(" TAG NULL. RETURNING !!!")); + pm8001_dbg(pm8001_ha, FAIL, " TAG NULL. RETURNING !!!\n"); return -1; } @@ -3783,23 +3639,21 @@ int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_dev = ccb->device; /* retrieve device */ if (!t) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk(" TASK NULL. RETURNING !!!")); + pm8001_dbg(pm8001_ha, FAIL, " TASK NULL. RETURNING !!!\n"); return -1; } ts = &t->task_status; if (status != 0) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task abort failed status 0x%x ," - "tag = 0x%x, scp= 0x%x\n", status, tag, scp)); + pm8001_dbg(pm8001_ha, FAIL, "task abort failed status 0x%x ,tag = 0x%x, scp= 0x%x\n", + status, tag, scp); switch (status) { case IO_SUCCESS: - PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); + pm8001_dbg(pm8001_ha, EH, "IO_SUCCESS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_GOOD; break; case IO_NOT_VALID: - PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_NOT_VALID\n")); + pm8001_dbg(pm8001_ha, EH, "IO_NOT_VALID\n"); ts->resp = TMF_RESP_FUNC_FAILED; break; } @@ -3844,14 +3698,13 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) struct sas_ha_struct *sas_ha = pm8001_ha->sas; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; - PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( - "SPC HW event for portid:%d, phyid:%d, event:%x, status:%x\n", - port_id, phy_id, eventType, status)); + pm8001_dbg(pm8001_ha, DEVIO, + "SPC HW event for portid:%d, phyid:%d, event:%x, status:%x\n", + port_id, phy_id, eventType, status); switch (eventType) { case HW_EVENT_PHY_START_STATUS: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_START_STATUS" - " status = %x\n", status)); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_START_STATUS status = %x\n", + status); if (status == 0) { phy->phy_state = 1; if (pm8001_ha->flags == PM8001F_RUN_TIME && @@ -3860,38 +3713,32 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) } break; case HW_EVENT_SAS_PHY_UP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_START_STATUS\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_START_STATUS\n"); hw_event_sas_phy_up(pm8001_ha, piomb); break; case HW_EVENT_SATA_PHY_UP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SATA_PHY_UP\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_PHY_UP\n"); hw_event_sata_phy_up(pm8001_ha, piomb); break; case HW_EVENT_PHY_STOP_STATUS: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_STOP_STATUS " - "status = %x\n", status)); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_STOP_STATUS status = %x\n", + status); if (status == 0) phy->phy_state = 0; break; case HW_EVENT_SATA_SPINUP_HOLD: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SATA_SPINUP_HOLD\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_SPINUP_HOLD\n"); sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD); break; case HW_EVENT_PHY_DOWN: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_DOWN\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_DOWN\n"); sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL); phy->phy_attached = 0; phy->phy_state = 0; hw_event_phy_down(pm8001_ha, piomb); break; case HW_EVENT_PORT_INVALID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_INVALID\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_INVALID\n"); sas_phy_disconnected(sas_phy); phy->phy_attached = 0; sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); @@ -3899,8 +3746,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) /* the broadcast change primitive received, tell the LIBSAS this event to revalidate the sas domain*/ case HW_EVENT_BROADCAST_CHANGE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_BROADCAST_CHANGE\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_CHANGE\n"); pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_BROADCAST_CHANGE, port_id, phy_id, 1, 0); spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); @@ -3909,23 +3755,21 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); break; case HW_EVENT_PHY_ERROR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_ERROR\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_ERROR\n"); sas_phy_disconnected(&phy->sas_phy); phy->phy_attached = 0; sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR); break; case HW_EVENT_BROADCAST_EXP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_BROADCAST_EXP\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_EXP\n"); spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); sas_phy->sas_prim = HW_EVENT_BROADCAST_EXP; spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); break; case HW_EVENT_LINK_ERR_INVALID_DWORD: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_INVALID_DWORD\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_INVALID_DWORD\n"); pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0); sas_phy_disconnected(sas_phy); @@ -3933,8 +3777,8 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_LINK_ERR_DISPARITY_ERROR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_DISPARITY_ERROR\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_DISPARITY_ERROR\n"); pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_DISPARITY_ERROR, port_id, phy_id, 0, 0); @@ -3943,8 +3787,8 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_LINK_ERR_CODE_VIOLATION: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_CODE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_CODE_VIOLATION\n"); pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_CODE_VIOLATION, port_id, phy_id, 0, 0); @@ -3953,8 +3797,8 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n"); pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH, port_id, phy_id, 0, 0); @@ -3963,39 +3807,34 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_MALFUNCTION: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_MALFUNCTION\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_MALFUNCTION\n"); break; case HW_EVENT_BROADCAST_SES: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_BROADCAST_SES\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_SES\n"); spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); sas_phy->sas_prim = HW_EVENT_BROADCAST_SES; spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); break; case HW_EVENT_INBOUND_CRC_ERROR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_INBOUND_CRC_ERROR\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_INBOUND_CRC_ERROR\n"); pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_INBOUND_CRC_ERROR, port_id, phy_id, 0, 0); break; case HW_EVENT_HARD_RESET_RECEIVED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_HARD_RESET_RECEIVED\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_HARD_RESET_RECEIVED\n"); sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET); break; case HW_EVENT_ID_FRAME_TIMEOUT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_ID_FRAME_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_ID_FRAME_TIMEOUT\n"); sas_phy_disconnected(sas_phy); phy->phy_attached = 0; sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_LINK_ERR_PHY_RESET_FAILED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n"); pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_PHY_RESET_FAILED, port_id, phy_id, 0, 0); @@ -4004,34 +3843,30 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_PORT_RESET_TIMER_TMO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RESET_TIMER_TMO\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_TIMER_TMO\n"); sas_phy_disconnected(sas_phy); phy->phy_attached = 0; sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_PORT_RECOVERY_TIMER_TMO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RECOVERY_TIMER_TMO\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_PORT_RECOVERY_TIMER_TMO\n"); sas_phy_disconnected(sas_phy); phy->phy_attached = 0; sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_PORT_RECOVER: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RECOVER\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RECOVER\n"); break; case HW_EVENT_PORT_RESET_COMPLETE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RESET_COMPLETE\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_COMPLETE\n"); break; case EVENT_BROADCAST_ASYNCH_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("EVENT_BROADCAST_ASYNCH_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n"); break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown event type = %x\n", eventType)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown event type = %x\n", + eventType); break; } return 0; @@ -4047,163 +3882,132 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) __le32 pHeader = *(__le32 *)piomb; u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF); - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("process_one_iomb:")); + pm8001_dbg(pm8001_ha, MSG, "process_one_iomb:\n"); switch (opc) { case OPC_OUB_ECHO: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("OPC_OUB_ECHO\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_ECHO\n"); break; case OPC_OUB_HW_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_HW_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_HW_EVENT\n"); mpi_hw_event(pm8001_ha, piomb); break; case OPC_OUB_SSP_COMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_COMP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_COMP\n"); mpi_ssp_completion(pm8001_ha, piomb); break; case OPC_OUB_SMP_COMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SMP_COMP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_COMP\n"); mpi_smp_completion(pm8001_ha, piomb); break; case OPC_OUB_LOCAL_PHY_CNTRL: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_LOCAL_PHY_CNTRL\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_LOCAL_PHY_CNTRL\n"); pm8001_mpi_local_phy_ctl(pm8001_ha, piomb); break; case OPC_OUB_DEV_REGIST: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEV_REGIST\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_REGIST\n"); pm8001_mpi_reg_resp(pm8001_ha, piomb); break; case OPC_OUB_DEREG_DEV: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("unregister the device\n")); + pm8001_dbg(pm8001_ha, MSG, "unregister the device\n"); pm8001_mpi_dereg_resp(pm8001_ha, piomb); break; case OPC_OUB_GET_DEV_HANDLE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_DEV_HANDLE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEV_HANDLE\n"); break; case OPC_OUB_SATA_COMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SATA_COMP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_COMP\n"); mpi_sata_completion(pm8001_ha, piomb); break; case OPC_OUB_SATA_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SATA_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_EVENT\n"); mpi_sata_event(pm8001_ha, piomb); break; case OPC_OUB_SSP_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_EVENT\n"); mpi_ssp_event(pm8001_ha, piomb); break; case OPC_OUB_DEV_HANDLE_ARRIV: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEV_HANDLE_ARRIV\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_HANDLE_ARRIV\n"); /*This is for target*/ break; case OPC_OUB_SSP_RECV_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_RECV_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_RECV_EVENT\n"); /*This is for target*/ break; case OPC_OUB_DEV_INFO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEV_INFO\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_INFO\n"); break; case OPC_OUB_FW_FLASH_UPDATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_FW_FLASH_UPDATE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_FW_FLASH_UPDATE\n"); pm8001_mpi_fw_flash_update_resp(pm8001_ha, piomb); break; case OPC_OUB_GPIO_RESPONSE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GPIO_RESPONSE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_RESPONSE\n"); break; case OPC_OUB_GPIO_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GPIO_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_EVENT\n"); break; case OPC_OUB_GENERAL_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GENERAL_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GENERAL_EVENT\n"); pm8001_mpi_general_event(pm8001_ha, piomb); break; case OPC_OUB_SSP_ABORT_RSP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_ABORT_RSP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_ABORT_RSP\n"); pm8001_mpi_task_abort_resp(pm8001_ha, piomb); break; case OPC_OUB_SATA_ABORT_RSP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SATA_ABORT_RSP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_ABORT_RSP\n"); pm8001_mpi_task_abort_resp(pm8001_ha, piomb); break; case OPC_OUB_SAS_DIAG_MODE_START_END: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_DIAG_MODE_START_END\n")); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_SAS_DIAG_MODE_START_END\n"); break; case OPC_OUB_SAS_DIAG_EXECUTE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_DIAG_EXECUTE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_DIAG_EXECUTE\n"); break; case OPC_OUB_GET_TIME_STAMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_TIME_STAMP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_TIME_STAMP\n"); break; case OPC_OUB_SAS_HW_EVENT_ACK: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_HW_EVENT_ACK\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_HW_EVENT_ACK\n"); break; case OPC_OUB_PORT_CONTROL: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_PORT_CONTROL\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_PORT_CONTROL\n"); break; case OPC_OUB_SMP_ABORT_RSP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SMP_ABORT_RSP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_ABORT_RSP\n"); pm8001_mpi_task_abort_resp(pm8001_ha, piomb); break; case OPC_OUB_GET_NVMD_DATA: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_NVMD_DATA\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_NVMD_DATA\n"); pm8001_mpi_get_nvmd_resp(pm8001_ha, piomb); break; case OPC_OUB_SET_NVMD_DATA: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SET_NVMD_DATA\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_NVMD_DATA\n"); pm8001_mpi_set_nvmd_resp(pm8001_ha, piomb); break; case OPC_OUB_DEVICE_HANDLE_REMOVAL: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEVICE_HANDLE_REMOVAL\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEVICE_HANDLE_REMOVAL\n"); break; case OPC_OUB_SET_DEVICE_STATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SET_DEVICE_STATE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEVICE_STATE\n"); pm8001_mpi_set_dev_state_resp(pm8001_ha, piomb); break; case OPC_OUB_GET_DEVICE_STATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_DEVICE_STATE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEVICE_STATE\n"); break; case OPC_OUB_SET_DEV_INFO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SET_DEV_INFO\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEV_INFO\n"); break; case OPC_OUB_SAS_RE_INITIALIZE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_RE_INITIALIZE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_RE_INITIALIZE\n"); break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown outbound Queue IOMB OPC = %x\n", - opc)); + pm8001_dbg(pm8001_ha, DEVIO, + "Unknown outbound Queue IOMB OPC = %x\n", + opc); break; } } @@ -4416,19 +4220,19 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, circularQ = &pm8001_ha->inbnd_q_tbl[0]; if (task->data_dir == DMA_NONE) { ATAP = 0x04; /* no data*/ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("no data\n")); + pm8001_dbg(pm8001_ha, IO, "no data\n"); } else if (likely(!task->ata_task.device_control_reg_update)) { if (task->ata_task.dma_xfer) { ATAP = 0x06; /* DMA */ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("DMA\n")); + pm8001_dbg(pm8001_ha, IO, "DMA\n"); } else { ATAP = 0x05; /* PIO*/ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("PIO\n")); + pm8001_dbg(pm8001_ha, IO, "PIO\n"); } if (task->ata_task.use_ncq && dev->sata_dev.class != ATA_DEV_ATAPI) { ATAP = 0x07; /* FPDMA */ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("FPDMA\n")); + pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); } } if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { @@ -4485,10 +4289,10 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&task->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task 0x%p resp 0x%x " - " stat 0x%x but aborted by upper layer " - "\n", task, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, + "task 0x%p resp 0x%x stat 0x%x but aborted by upper layer\n", + task, ts->resp, + ts->stat); pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); } else { spin_unlock_irqrestore(&task->task_state_lock, @@ -4637,8 +4441,8 @@ int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha, memset(&payload, 0, sizeof(payload)); payload.tag = cpu_to_le32(1); payload.device_id = cpu_to_le32(device_id); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("unregister device device_id = %d\n", device_id)); + pm8001_dbg(pm8001_ha, MSG, "unregister device device_id = %d\n", + device_id); ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, sizeof(payload), 0); return ret; @@ -4690,9 +4494,9 @@ static irqreturn_t pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec) { pm8001_chip_interrupt_disable(pm8001_ha, vec); - PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( - "irq vec %d, ODMR:0x%x\n", - vec, pm8001_cr32(pm8001_ha, 0, 0x30))); + pm8001_dbg(pm8001_ha, DEVIO, + "irq vec %d, ODMR:0x%x\n", + vec, pm8001_cr32(pm8001_ha, 0, 0x30)); process_oq(pm8001_ha, vec); pm8001_chip_interrupt_enable(pm8001_ha, vec); return IRQ_HANDLED; @@ -4729,9 +4533,8 @@ int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha, { u32 opc, device_id; int rc = TMF_RESP_FUNC_FAILED; - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("cmd_tag = %x, abort task tag = 0x%x", - cmd_tag, task_tag)); + pm8001_dbg(pm8001_ha, EH, "cmd_tag = %x, abort task tag = 0x%x\n", + cmd_tag, task_tag); if (pm8001_dev->dev_type == SAS_END_DEVICE) opc = OPC_INB_SSP_ABORT; else if (pm8001_dev->dev_type == SAS_SATA_DEV) @@ -4742,7 +4545,7 @@ int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha, rc = send_task_abort(pm8001_ha, opc, device_id, flag, task_tag, cmd_tag); if (rc != TMF_RESP_FUNC_COMPLETE) - PM8001_EH_DBG(pm8001_ha, pm8001_printk("rc= %d\n", rc)); + pm8001_dbg(pm8001_ha, EH, "rc= %d\n", rc); return rc; } @@ -5008,8 +4811,9 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, if (!fw_control_context) return -ENOMEM; fw_control = (struct fw_control_info *)&ioctl_payload->func_specific; - PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( - "dma fw_control context input length :%x\n", fw_control->len)); + pm8001_dbg(pm8001_ha, DEVIO, + "dma fw_control context input length :%x\n", + fw_control->len); memcpy(buffer, fw_control->buffer, fw_control->len); flash_update_info.sgl.addr = cpu_to_le64(phys_addr); flash_update_info.sgl.im_len.len = cpu_to_le32(fw_control->len); diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 3cf3e58b6979..ee2de177d0d0 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -271,15 +271,14 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, spin_lock_init(&pm8001_ha->lock); spin_lock_init(&pm8001_ha->bitmap_lock); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("pm8001_alloc: PHY:%x\n", - pm8001_ha->chip->n_phy)); + pm8001_dbg(pm8001_ha, INIT, "pm8001_alloc: PHY:%x\n", + pm8001_ha->chip->n_phy); /* Setup Interrupt */ rc = pm8001_setup_irq(pm8001_ha); if (rc) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "pm8001_setup_irq failed [ret: %d]\n", rc)); + pm8001_dbg(pm8001_ha, FAIL, + "pm8001_setup_irq failed [ret: %d]\n", rc); goto err_out_shost; } /* Request Interrupt */ @@ -387,17 +386,17 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size = 0x10000; pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000; for (i = 0; i < pm8001_ha->max_memcnt; i++) { + struct mpi_mem *region = &pm8001_ha->memoryMap.region[i]; + if (pm8001_mem_alloc(pm8001_ha->pdev, - &pm8001_ha->memoryMap.region[i].virt_ptr, - &pm8001_ha->memoryMap.region[i].phys_addr, - &pm8001_ha->memoryMap.region[i].phys_addr_hi, - &pm8001_ha->memoryMap.region[i].phys_addr_lo, - pm8001_ha->memoryMap.region[i].total_len, - pm8001_ha->memoryMap.region[i].alignment) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Mem%d alloc failed\n", - i)); - goto err_out; + ®ion->virt_ptr, + ®ion->phys_addr, + ®ion->phys_addr_hi, + ®ion->phys_addr_lo, + region->total_len, + region->alignment) != 0) { + pm8001_dbg(pm8001_ha, FAIL, "Mem%d alloc failed\n", i); + goto err_out; } } @@ -412,7 +411,7 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, pm8001_ha->devices[i].dev_type = SAS_PHY_UNUSED; pm8001_ha->devices[i].id = i; pm8001_ha->devices[i].device_id = PM8001_MAX_DEVICES; - pm8001_ha->devices[i].running_req = 0; + atomic_set(&pm8001_ha->devices[i].running_req, 0); } pm8001_ha->flags = PM8001F_INIT_TIME; /* Initialize tags */ @@ -467,15 +466,15 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha) pm8001_ha->io_mem[logicalBar].memvirtaddr = ioremap(pm8001_ha->io_mem[logicalBar].membase, pm8001_ha->io_mem[logicalBar].memsize); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCI: bar %d, logicalBar %d ", - bar, logicalBar)); - PM8001_INIT_DBG(pm8001_ha, pm8001_printk( - "base addr %llx virt_addr=%llx len=%d\n", - (u64)pm8001_ha->io_mem[logicalBar].membase, - (u64)(unsigned long) - pm8001_ha->io_mem[logicalBar].memvirtaddr, - pm8001_ha->io_mem[logicalBar].memsize)); + pm8001_dbg(pm8001_ha, INIT, + "PCI: bar %d, logicalBar %d\n", + bar, logicalBar); + pm8001_dbg(pm8001_ha, INIT, + "base addr %llx virt_addr=%llx len=%d\n", + (u64)pm8001_ha->io_mem[logicalBar].membase, + (u64)(unsigned long) + pm8001_ha->io_mem[logicalBar].memvirtaddr, + pm8001_ha->io_mem[logicalBar].memsize); } else { pm8001_ha->io_mem[logicalBar].membase = 0; pm8001_ha->io_mem[logicalBar].memsize = 0; @@ -520,8 +519,8 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, else { pm8001_ha->link_rate = LINKRATE_15 | LINKRATE_30 | LINKRATE_60 | LINKRATE_120; - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "Setting link rate to default value\n")); + pm8001_dbg(pm8001_ha, FAIL, + "Setting link rate to default value\n"); } sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id); /* IOMB size is 128 for 8088/89 controllers */ @@ -684,13 +683,13 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) payload.offset = 0; payload.func_specific = kzalloc(payload.rd_length, GFP_KERNEL); if (!payload.func_specific) { - PM8001_INIT_DBG(pm8001_ha, pm8001_printk("mem alloc fail\n")); + pm8001_dbg(pm8001_ha, INIT, "mem alloc fail\n"); return; } rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); if (rc) { kfree(payload.func_specific); - PM8001_INIT_DBG(pm8001_ha, pm8001_printk("nvmd failed\n")); + pm8001_dbg(pm8001_ha, INIT, "nvmd failed\n"); return; } wait_for_completion(&completion); @@ -718,9 +717,8 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) sas_add[7] = sas_add[7] + 4; memcpy(&pm8001_ha->phy[i].dev_sas_addr, sas_add, SAS_ADDR_SIZE); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("phy %d sas_addr = %016llx\n", i, - pm8001_ha->phy[i].dev_sas_addr)); + pm8001_dbg(pm8001_ha, INIT, "phy %d sas_addr = %016llx\n", i, + pm8001_ha->phy[i].dev_sas_addr); } kfree(payload.func_specific); #else @@ -760,7 +758,7 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); if (rc) { kfree(payload.func_specific); - PM8001_INIT_DBG(pm8001_ha, pm8001_printk("nvmd failed\n")); + pm8001_dbg(pm8001_ha, INIT, "nvmd failed\n"); return -ENOMEM; } wait_for_completion(&completion); @@ -854,9 +852,9 @@ void pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask) break; default: - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Unknown subsystem device=0x%.04x", - pm8001_ha->pdev->subsystem_device)); + pm8001_dbg(pm8001_ha, INIT, + "Unknown subsystem device=0x%.04x\n", + pm8001_ha->pdev->subsystem_device); } } @@ -950,9 +948,9 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) /* Maximum queue number updating in HBA structure */ pm8001_ha->max_q_num = number_of_intr; - PM8001_INIT_DBG(pm8001_ha, pm8001_printk( - "pci_alloc_irq_vectors request ret:%d no of intr %d\n", - rc, pm8001_ha->number_of_intr)); + pm8001_dbg(pm8001_ha, INIT, + "pci_alloc_irq_vectors request ret:%d no of intr %d\n", + rc, pm8001_ha->number_of_intr); return 0; } @@ -964,9 +962,9 @@ static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha) if (pm8001_ha->chip_id != chip_8001) flag &= ~IRQF_SHARED; - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("pci_enable_msix request number of intr %d\n", - pm8001_ha->number_of_intr)); + pm8001_dbg(pm8001_ha, INIT, + "pci_enable_msix request number of intr %d\n", + pm8001_ha->number_of_intr); for (i = 0; i < pm8001_ha->number_of_intr; i++) { snprintf(pm8001_ha->intr_drvname[i], @@ -1002,8 +1000,7 @@ static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha) #ifdef PM8001_USE_MSIX if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) return pm8001_setup_msix(pm8001_ha); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MSIX not supported!!!\n")); + pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n"); #endif return 0; } @@ -1023,8 +1020,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) if (pdev->msix_cap && pci_msi_enabled()) return pm8001_request_msix(pm8001_ha); else { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MSIX not supported!!!\n")); + pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n"); goto intx; } #endif @@ -1108,8 +1104,8 @@ static int pm8001_pci_probe(struct pci_dev *pdev, PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); if (rc) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "chip_init failed [ret: %d]\n", rc)); + pm8001_dbg(pm8001_ha, FAIL, + "chip_init failed [ret: %d]\n", rc); goto err_out_ha_free; } @@ -1131,14 +1127,15 @@ static int pm8001_pci_probe(struct pci_dev *pdev, pm8001_init_sas_add(pm8001_ha); /* phy setting support for motherboard controller */ - if (pm8001_configure_phy_settings(pm8001_ha)) + rc = pm8001_configure_phy_settings(pm8001_ha); + if (rc) goto err_out_shost; pm8001_post_sas_ha_init(shost, chip); rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); if (rc) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "sas_register_ha failed [ret: %d]\n", rc)); + pm8001_dbg(pm8001_ha, FAIL, + "sas_register_ha failed [ret: %d]\n", rc); goto err_out_shost; } list_add_tail(&pm8001_ha->list, &hba_list); @@ -1187,11 +1184,11 @@ pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost, goto err_out; /* Memory region for ccb_info*/ - pm8001_ha->ccb_info = (struct pm8001_ccb_info *) + pm8001_ha->ccb_info = kcalloc(ccb_count, sizeof(struct pm8001_ccb_info), GFP_KERNEL); if (!pm8001_ha->ccb_info) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk - ("Unable to allocate memory for ccb\n")); + pm8001_dbg(pm8001_ha, FAIL, + "Unable to allocate memory for ccb\n"); goto err_out_noccb; } for (i = 0; i < ccb_count; i++) { @@ -1199,8 +1196,8 @@ pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost, sizeof(struct pm8001_prd) * PM8001_MAX_DMA_SG, &pm8001_ha->ccb_info[i].ccb_dma_handle); if (!pm8001_ha->ccb_info[i].buf_prd) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk - ("pm80xx: ccb prd memory allocation error\n")); + pm8001_dbg(pm8001_ha, FAIL, + "pm80xx: ccb prd memory allocation error\n"); goto err_out; } pm8001_ha->ccb_info[i].task = NULL; @@ -1257,23 +1254,21 @@ static void pm8001_pci_remove(struct pci_dev *pdev) /** * pm8001_pci_suspend - power management suspend main entry point - * @pdev: PCI device struct - * @state: PM state change to (usually PCI_D3) + * @dev: Device struct * * Returns 0 success, anything else error. */ -static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused pm8001_pci_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct sas_ha_struct *sha = pci_get_drvdata(pdev); - struct pm8001_hba_info *pm8001_ha; + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; int i, j; - u32 device_state; - pm8001_ha = sha->lldd_ha; sas_suspend_ha(sha); flush_workqueue(pm8001_wq); scsi_block_requests(pm8001_ha->shost); if (!pdev->pm_cap) { - dev_err(&pdev->dev, " PCI PM not supported\n"); + dev_err(dev, " PCI PM not supported\n"); return -ENODEV; } PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF); @@ -1296,24 +1291,21 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state) for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) tasklet_kill(&pm8001_ha->tasklet[j]); #endif - device_state = pci_choose_state(pdev, state); - pm8001_printk("pdev=0x%p, slot=%s, entering " - "operating state [D%d]\n", pdev, - pm8001_ha->name, device_state); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, device_state); + pm8001_info(pm8001_ha, "pdev=0x%p, slot=%s, entering " + "suspended state\n", pdev, + pm8001_ha->name); return 0; } /** * pm8001_pci_resume - power management resume main entry point - * @pdev: PCI device struct + * @dev: Device struct * * Returns 0 success, anything else error. */ -static int pm8001_pci_resume(struct pci_dev *pdev) +static int __maybe_unused pm8001_pci_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct sas_ha_struct *sha = pci_get_drvdata(pdev); struct pm8001_hba_info *pm8001_ha; int rc; @@ -1323,20 +1315,9 @@ static int pm8001_pci_resume(struct pci_dev *pdev) pm8001_ha = sha->lldd_ha; device_state = pdev->current_state; - pm8001_printk("pdev=0x%p, slot=%s, resuming from previous " - "operating state [D%d]\n", pdev, pm8001_ha->name, device_state); + pm8001_info(pm8001_ha, "pdev=0x%p, slot=%s, resuming from previous operating state [D%d]\n", + pdev, pm8001_ha->name, device_state); - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - rc = pci_enable_device(pdev); - if (rc) { - pm8001_printk("slot=%s Enable device failed during resume\n", - pm8001_ha->name); - goto err_out_enable; - } - - pci_set_master(pdev); rc = pci_go_44(pdev); if (rc) goto err_out_disable; @@ -1344,8 +1325,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev) /* chip soft rst only for spc */ if (pm8001_ha->chip_id == chip_8001) { PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("chip soft reset successful\n")); + pm8001_dbg(pm8001_ha, INIT, "chip soft reset successful\n"); } rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); if (rc) @@ -1397,8 +1377,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev) err_out_disable: scsi_remove_host(pm8001_ha->shost); - pci_disable_device(pdev); -err_out_enable: + return rc; } @@ -1481,13 +1460,16 @@ static struct pci_device_id pm8001_pci_table[] = { {} /* terminate list */ }; +static SIMPLE_DEV_PM_OPS(pm8001_pci_pm_ops, + pm8001_pci_suspend, + pm8001_pci_resume); + static struct pci_driver pm8001_pci_driver = { .name = DRV_NAME, .id_table = pm8001_pci_table, .probe = pm8001_pci_probe, .remove = pm8001_pci_remove, - .suspend = pm8001_pci_suspend, - .resume = pm8001_pci_resume, + .driver.pm = &pm8001_pci_pm_ops, }; /** diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 9889bab7d31c..d1e9dba2ef19 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -250,8 +250,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, spin_unlock_irqrestore(&pm8001_ha->lock, flags); return 0; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("func 0x%x\n", func)); + pm8001_dbg(pm8001_ha, DEVIO, "func 0x%x\n", func); rc = -EOPNOTSUPP; } msleep(300); @@ -405,7 +404,7 @@ static int pm8001_task_exec(struct sas_task *task, t->task_done(t); return 0; } - PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n ")); + pm8001_dbg(pm8001_ha, IO, "pm8001_task_exec device\n"); spin_lock_irqsave(&pm8001_ha->lock, flags); do { dev = t->dev; @@ -456,9 +455,11 @@ static int pm8001_task_exec(struct sas_task *task, ccb->device = pm8001_dev; switch (task_proto) { case SAS_PROTOCOL_SMP: + atomic_inc(&pm8001_dev->running_req); rc = pm8001_task_prep_smp(pm8001_ha, ccb); break; case SAS_PROTOCOL_SSP: + atomic_inc(&pm8001_dev->running_req); if (is_tmf) rc = pm8001_task_prep_ssp_tm(pm8001_ha, ccb, tmf); @@ -467,6 +468,7 @@ static int pm8001_task_exec(struct sas_task *task, break; case SAS_PROTOCOL_SATA: case SAS_PROTOCOL_STP: + atomic_inc(&pm8001_dev->running_req); rc = pm8001_task_prep_ata(pm8001_ha, ccb); break; default: @@ -477,15 +479,14 @@ static int pm8001_task_exec(struct sas_task *task, } if (rc) { - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("rc is %x\n", rc)); + pm8001_dbg(pm8001_ha, IO, "rc is %x\n", rc); + atomic_dec(&pm8001_dev->running_req); goto err_out_tag; } /* TODO: select normal or high priority */ spin_lock(&t->task_state_lock); t->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock(&t->task_state_lock); - pm8001_dev->running_req++; } while (0); rc = 0; goto out_done; @@ -567,9 +568,9 @@ static struct pm8001_device *pm8001_alloc_dev(struct pm8001_hba_info *pm8001_ha) } } if (dev == PM8001_MAX_DEVICES) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("max support %d devices, ignore ..\n", - PM8001_MAX_DEVICES)); + pm8001_dbg(pm8001_ha, FAIL, + "max support %d devices, ignore ..\n", + PM8001_MAX_DEVICES); } return NULL; } @@ -587,8 +588,7 @@ struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha, return &pm8001_ha->devices[dev]; } if (dev == PM8001_MAX_DEVICES) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("NO MATCHING " - "DEVICE FOUND !!!\n")); + pm8001_dbg(pm8001_ha, FAIL, "NO MATCHING DEVICE FOUND !!!\n"); } return NULL; } @@ -649,10 +649,10 @@ static int pm8001_dev_found_notify(struct domain_device *dev) } } if (phy_id == parent_dev->ex_dev.num_phys) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Error: no attached dev:%016llx" - " at ex:%016llx.\n", SAS_ADDR(dev->sas_addr), - SAS_ADDR(parent_dev->sas_addr))); + pm8001_dbg(pm8001_ha, FAIL, + "Error: no attached dev:%016llx at ex:%016llx.\n", + SAS_ADDR(dev->sas_addr), + SAS_ADDR(parent_dev->sas_addr)); res = -1; } } else { @@ -662,7 +662,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev) flag = 1; /* directly sata */ } } /*register this device to HBA*/ - PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n")); + pm8001_dbg(pm8001_ha, DISC, "Found device\n"); PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag); spin_unlock_irqrestore(&pm8001_ha->lock, flags); wait_for_completion(&completion); @@ -734,9 +734,7 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev, if (res) { del_timer(&task->slow_task->timer); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Executing internal task " - "failed\n")); + pm8001_dbg(pm8001_ha, FAIL, "Executing internal task failed\n"); goto ex_err; } wait_for_completion(&task->slow_task->completion); @@ -750,9 +748,9 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev, /* Even TMF timed out, return direct. */ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TMF task[%x]timeout.\n", - tmf->tmf)); + pm8001_dbg(pm8001_ha, FAIL, + "TMF task[%x]timeout.\n", + tmf->tmf); goto ex_err; } } @@ -773,17 +771,15 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev, if (task->task_status.resp == SAS_TASK_COMPLETE && task->task_status.stat == SAS_DATA_OVERRUN) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Blocked task error.\n")); + pm8001_dbg(pm8001_ha, FAIL, "Blocked task error.\n"); res = -EMSGSIZE; break; } else { - PM8001_EH_DBG(pm8001_ha, - pm8001_printk(" Task to dev %016llx response:" - "0x%x status 0x%x\n", - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat)); + pm8001_dbg(pm8001_ha, EH, + " Task to dev %016llx response:0x%x status 0x%x\n", + SAS_ADDR(dev->sas_addr), + task->task_status.resp, + task->task_status.stat); sas_free_task(task); task = NULL; } @@ -830,9 +826,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, if (res) { del_timer(&task->slow_task->timer); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Executing internal task " - "failed\n")); + pm8001_dbg(pm8001_ha, FAIL, "Executing internal task failed\n"); goto ex_err; } wait_for_completion(&task->slow_task->completion); @@ -840,8 +834,8 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, /* Even TMF timed out, return direct. */ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TMF task timeout.\n")); + pm8001_dbg(pm8001_ha, FAIL, + "TMF task timeout.\n"); goto ex_err; } } @@ -852,12 +846,11 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, break; } else { - PM8001_EH_DBG(pm8001_ha, - pm8001_printk(" Task to dev %016llx response: " - "0x%x status 0x%x\n", - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat)); + pm8001_dbg(pm8001_ha, EH, + " Task to dev %016llx response: 0x%x status 0x%x\n", + SAS_ADDR(dev->sas_addr), + task->task_status.resp, + task->task_status.stat); sas_free_task(task); task = NULL; } @@ -883,22 +876,20 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) if (pm8001_dev) { u32 device_id = pm8001_dev->device_id; - PM8001_DISC_DBG(pm8001_ha, - pm8001_printk("found dev[%d:%x] is gone.\n", - pm8001_dev->device_id, pm8001_dev->dev_type)); - if (pm8001_dev->running_req) { + pm8001_dbg(pm8001_ha, DISC, "found dev[%d:%x] is gone.\n", + pm8001_dev->device_id, pm8001_dev->dev_type); + if (atomic_read(&pm8001_dev->running_req)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , dev, 1, 0); - while (pm8001_dev->running_req) + while (atomic_read(&pm8001_dev->running_req)) msleep(20); spin_lock_irqsave(&pm8001_ha->lock, flags); } PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id); pm8001_free_dev(pm8001_dev); } else { - PM8001_DISC_DBG(pm8001_ha, - pm8001_printk("Found dev has gone.\n")); + pm8001_dbg(pm8001_ha, DISC, "Found dev has gone.\n"); } dev->lldd_dev = NULL; spin_unlock_irqrestore(&pm8001_ha->lock, flags); @@ -916,7 +907,7 @@ static int pm8001_issue_ssp_tmf(struct domain_device *dev, if (!(dev->tproto & SAS_PROTOCOL_SSP)) return TMF_RESP_FUNC_ESUPP; - strncpy((u8 *)&ssp_task.LUN, lun, 8); + memcpy((u8 *)&ssp_task.LUN, lun, 8); return pm8001_exec_internal_tmf_task(dev, &ssp_task, sizeof(ssp_task), tmf); } @@ -968,7 +959,7 @@ void pm8001_open_reject_retry( ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); spin_lock_irqsave(&task->task_state_lock, flags1); task->task_state_flags &= ~SAS_TASK_STATE_PENDING; task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; @@ -1018,9 +1009,9 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev) } rc = sas_phy_reset(phy, 1); if (rc) { - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("phy reset failed for device %x\n" - "with rc %d\n", pm8001_dev->device_id, rc)); + pm8001_dbg(pm8001_ha, EH, + "phy reset failed for device %x\n" + "with rc %d\n", pm8001_dev->device_id, rc); rc = TMF_RESP_FUNC_FAILED; goto out; } @@ -1028,17 +1019,16 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev) rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , dev, 1, 0); if (rc) { - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("task abort failed %x\n" - "with rc %d\n", pm8001_dev->device_id, rc)); + pm8001_dbg(pm8001_ha, EH, "task abort failed %x\n" + "with rc %d\n", pm8001_dev->device_id, rc); rc = TMF_RESP_FUNC_FAILED; } } else { rc = sas_phy_reset(phy, 1); msleep(2000); } - PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n", - pm8001_dev->device_id, rc)); + pm8001_dbg(pm8001_ha, EH, " for device[%x]:rc=%d\n", + pm8001_dev->device_id, rc); out: sas_put_local_phy(phy); return rc; @@ -1061,8 +1051,7 @@ int pm8001_I_T_nexus_event_handler(struct domain_device *dev) pm8001_dev = dev->lldd_dev; pm8001_ha = pm8001_find_ha_by_dev(dev); - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("I_T_Nexus handler invoked !!")); + pm8001_dbg(pm8001_ha, EH, "I_T_Nexus handler invoked !!\n"); phy = sas_get_local_phy(dev); @@ -1101,8 +1090,8 @@ int pm8001_I_T_nexus_event_handler(struct domain_device *dev) rc = sas_phy_reset(phy, 1); msleep(2000); } - PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n", - pm8001_dev->device_id, rc)); + pm8001_dbg(pm8001_ha, EH, " for device[%x]:rc=%d\n", + pm8001_dev->device_id, rc); out: sas_put_local_phy(phy); @@ -1131,8 +1120,8 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun) rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task); } /* If failed, fall-through I_T_Nexus reset */ - PM8001_EH_DBG(pm8001_ha, pm8001_printk("for device[%x]:rc=%d\n", - pm8001_dev->device_id, rc)); + pm8001_dbg(pm8001_ha, EH, "for device[%x]:rc=%d\n", + pm8001_dev->device_id, rc); return rc; } @@ -1140,7 +1129,6 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun) int pm8001_query_task(struct sas_task *task) { u32 tag = 0xdeadbeef; - int i = 0; struct scsi_lun lun; struct pm8001_tmf_task tmf_task; int rc = TMF_RESP_FUNC_FAILED; @@ -1159,10 +1147,7 @@ int pm8001_query_task(struct sas_task *task) rc = TMF_RESP_FUNC_FAILED; return rc; } - PM8001_EH_DBG(pm8001_ha, pm8001_printk("Query:[")); - for (i = 0; i < 16; i++) - printk(KERN_INFO "%02x ", cmnd->cmnd[i]); - printk(KERN_INFO "]\n"); + pm8001_dbg(pm8001_ha, EH, "Query:[%16ph]\n", cmnd->cmnd); tmf_task.tmf = TMF_QUERY_TASK; tmf_task.tag_of_task_to_be_managed = tag; @@ -1170,15 +1155,14 @@ int pm8001_query_task(struct sas_task *task) switch (rc) { /* The task is still in Lun, release it then */ case TMF_RESP_FUNC_SUCC: - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("The task is still in Lun\n")); + pm8001_dbg(pm8001_ha, EH, + "The task is still in Lun\n"); break; /* The task is not in Lun or failed, reset the phy */ case TMF_RESP_FUNC_FAILED: case TMF_RESP_FUNC_COMPLETE: - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("The task is not in Lun or failed," - " reset the phy\n")); + pm8001_dbg(pm8001_ha, EH, + "The task is not in Lun or failed, reset the phy\n"); break; } } @@ -1207,7 +1191,7 @@ int pm8001_abort_task(struct sas_task *task) phy_id = pm8001_dev->attached_phy; ret = pm8001_find_tag(task, &tag); if (ret == 0) { - pm8001_printk("no tag for task:%p\n", task); + pm8001_info(pm8001_ha, "no tag for task:%p\n", task); return TMF_RESP_FUNC_FAILED; } spin_lock_irqsave(&task->task_state_lock, flags); @@ -1264,8 +1248,8 @@ int pm8001_abort_task(struct sas_task *task) * leaking the task in libsas or losing the race and * getting a double free. */ - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Waiting for local phy ctl\n")); + pm8001_dbg(pm8001_ha, MSG, + "Waiting for local phy ctl\n"); ret = wait_for_completion_timeout(&completion, PM8001_TASK_TIMEOUT * HZ); if (!ret || !phy->reset_success) { @@ -1275,8 +1259,8 @@ int pm8001_abort_task(struct sas_task *task) /* 3. Wait for Port Reset complete or * Port reset TMO */ - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Waiting for Port reset\n")); + pm8001_dbg(pm8001_ha, MSG, + "Waiting for Port reset\n"); ret = wait_for_completion_timeout( &completion_reset, PM8001_TASK_TIMEOUT * HZ); @@ -1329,7 +1313,7 @@ out: task->slow_task = NULL; spin_unlock_irqrestore(&task->task_state_lock, flags); if (rc != TMF_RESP_FUNC_COMPLETE) - pm8001_printk("rc= %d\n", rc); + pm8001_info(pm8001_ha, "rc= %d\n", rc); return rc; } @@ -1355,9 +1339,8 @@ int pm8001_clear_task_set(struct domain_device *dev, u8 *lun) struct pm8001_device *pm8001_dev = dev->lldd_dev; struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("I_T_L_Q clear task set[%x]\n", - pm8001_dev->device_id)); + pm8001_dbg(pm8001_ha, EH, "I_T_L_Q clear task set[%x]\n", + pm8001_dev->device_id); tmf_task.tmf = TMF_CLEAR_TASK_SET; return pm8001_issue_ssp_tmf(dev, lun, &tmf_task); } diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 95663e138083..f2c8cbad3853 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -69,45 +69,16 @@ #define PM8001_DEV_LOGGING 0x80 /* development message logging */ #define PM8001_DEVIO_LOGGING 0x100 /* development io message logging */ #define PM8001_IOERR_LOGGING 0x200 /* development io err message logging */ -#define pm8001_printk(format, arg...) pr_info("%s:: %s %d:" \ - format, pm8001_ha->name, __func__, __LINE__, ## arg) -#define PM8001_CHECK_LOGGING(HBA, LEVEL, CMD) \ -do { \ - if (unlikely(HBA->logging_level & LEVEL)) \ - do { \ - CMD; \ - } while (0); \ -} while (0); -#define PM8001_EH_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_EH_LOGGING, CMD) +#define pm8001_info(HBA, fmt, ...) \ + pr_info("%s:: %s %d:" fmt, \ + (HBA)->name, __func__, __LINE__, ##__VA_ARGS__) -#define PM8001_INIT_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_INIT_LOGGING, CMD) - -#define PM8001_DISC_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_DISC_LOGGING, CMD) - -#define PM8001_IO_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_IO_LOGGING, CMD) - -#define PM8001_FAIL_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_FAIL_LOGGING, CMD) - -#define PM8001_IOCTL_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_IOCTL_LOGGING, CMD) - -#define PM8001_MSG_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_MSG_LOGGING, CMD) - -#define PM8001_DEV_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_DEV_LOGGING, CMD) - -#define PM8001_DEVIO_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_DEVIO_LOGGING, CMD) - -#define PM8001_IOERR_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_IOERR_LOGGING, CMD) +#define pm8001_dbg(HBA, level, fmt, ...) \ +do { \ + if (unlikely((HBA)->logging_level & PM8001_##level##_LOGGING)) \ + pm8001_info(HBA, fmt, ##__VA_ARGS__); \ +} while (0) #define PM8001_USE_TASKLET #define PM8001_USE_MSIX @@ -293,7 +264,7 @@ struct pm8001_device { struct completion *dcompletion; struct completion *setds_completion; u32 device_id; - u32 running_req; + atomic_t running_req; }; struct pm8001_prd_imt { diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 7593f248afb2..6772b0924dac 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -58,9 +58,8 @@ int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value) reg_val = pm8001_cr32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER); } while ((reg_val != shift_value) && time_before(jiffies, start)); if (reg_val != shift_value) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER" - " = 0x%x\n", reg_val)); + pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:MEMBASE_II_SHIFT_REGISTER = 0x%x\n", + reg_val); return -1; } return 0; @@ -109,8 +108,8 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, } /* initialize variables for very first call from host application */ if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("forensic_info TYPE_NON_FATAL..............\n")); + pm8001_dbg(pm8001_ha, IO, + "forensic_info TYPE_NON_FATAL..............\n"); direct_data = (u8 *)fatal_error_data; pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL; pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET; @@ -123,17 +122,13 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, MPI_FATAL_EDUMP_TABLE_SIGNATURE, 0x1234abcd); pm8001_ha->forensic_info.data_buf.direct_data = direct_data; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("ossaHwCB: status1 %d\n", status)); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("ossaHwCB: read_len 0x%x\n", - pm8001_ha->forensic_info.data_buf.read_len)); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("ossaHwCB: direct_len 0x%x\n", - pm8001_ha->forensic_info.data_buf.direct_len)); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("ossaHwCB: direct_offset 0x%x\n", - pm8001_ha->forensic_info.data_buf.direct_offset)); + pm8001_dbg(pm8001_ha, IO, "ossaHwCB: status1 %d\n", status); + pm8001_dbg(pm8001_ha, IO, "ossaHwCB: read_len 0x%x\n", + pm8001_ha->forensic_info.data_buf.read_len); + pm8001_dbg(pm8001_ha, IO, "ossaHwCB: direct_len 0x%x\n", + pm8001_ha->forensic_info.data_buf.direct_len); + pm8001_dbg(pm8001_ha, IO, "ossaHwCB: direct_offset 0x%x\n", + pm8001_ha->forensic_info.data_buf.direct_offset); } if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { /* start to get data */ @@ -153,29 +148,24 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, */ length_to_read = accum_len - pm8001_ha->forensic_preserved_accumulated_transfer; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv: accum_len 0x%x\n", accum_len)); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv: length_to_read 0x%x\n", - length_to_read)); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv: last_offset 0x%x\n", - pm8001_ha->forensic_last_offset)); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv: read_len 0x%x\n", - pm8001_ha->forensic_info.data_buf.read_len)); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv:: direct_len 0x%x\n", - pm8001_ha->forensic_info.data_buf.direct_len)); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv:: direct_offset 0x%x\n", - pm8001_ha->forensic_info.data_buf.direct_offset)); + pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: accum_len 0x%x\n", + accum_len); + pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: length_to_read 0x%x\n", + length_to_read); + pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: last_offset 0x%x\n", + pm8001_ha->forensic_last_offset); + pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: read_len 0x%x\n", + pm8001_ha->forensic_info.data_buf.read_len); + pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv:: direct_len 0x%x\n", + pm8001_ha->forensic_info.data_buf.direct_len); + pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv:: direct_offset 0x%x\n", + pm8001_ha->forensic_info.data_buf.direct_offset); /* If accumulated length failed to read correctly fail the attempt.*/ if (accum_len == 0xFFFFFFFF) { - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("Possible PCI issue 0x%x not expected\n", - accum_len)); + pm8001_dbg(pm8001_ha, IO, + "Possible PCI issue 0x%x not expected\n", + accum_len); return status; } /* If accumulated length is zero fail the attempt */ @@ -239,8 +229,8 @@ moreData: offset = (int) ((char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv:return1 0x%x\n", offset)); + pm8001_dbg(pm8001_ha, IO, + "get_fatal_spcv:return1 0x%x\n", offset); return (char *)pm8001_ha-> forensic_info.data_buf.direct_data - (char *)buf; @@ -262,8 +252,8 @@ moreData: offset = (int) ((char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv:return2 0x%x\n", offset)); + pm8001_dbg(pm8001_ha, IO, + "get_fatal_spcv:return2 0x%x\n", offset); return (char *)pm8001_ha-> forensic_info.data_buf.direct_data - (char *)buf; @@ -289,8 +279,8 @@ moreData: offset = (int) ((char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv: return3 0x%x\n", offset)); + pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: return3 0x%x\n", + offset); return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; } @@ -327,9 +317,9 @@ moreData: } while ((reg_val) && time_before(jiffies, start)); if (reg_val != 0) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "TIMEOUT:MPI_FATAL_EDUMP_TABLE_HDSHAKE 0x%x\n", - reg_val)); + pm8001_dbg(pm8001_ha, FAIL, + "TIMEOUT:MPI_FATAL_EDUMP_TABLE_HDSHAKE 0x%x\n", + reg_val); /* Fail the dump if a timeout occurs */ pm8001_ha->forensic_info.data_buf.direct_data += sprintf( @@ -351,9 +341,9 @@ moreData: time_before(jiffies, start)); if (reg_val < 2) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "TIMEOUT:MPI_FATAL_EDUMP_TABLE_STATUS = 0x%x\n", - reg_val)); + pm8001_dbg(pm8001_ha, FAIL, + "TIMEOUT:MPI_FATAL_EDUMP_TABLE_STATUS = 0x%x\n", + reg_val); /* Fail the dump if a timeout occurs */ pm8001_ha->forensic_info.data_buf.direct_data += sprintf( @@ -387,8 +377,7 @@ moreData: } offset = (int)((char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("get_fatal_spcv: return4 0x%x\n", offset)); + pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: return4 0x%x\n", offset); return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; } @@ -419,8 +408,7 @@ ssize_t pm80xx_get_non_fatal_dump(struct device *cdev, PAGE_SIZE, "Not supported for SPC controller"); return 0; } - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("forensic_info TYPE_NON_FATAL...\n")); + pm8001_dbg(pm8001_ha, IO, "forensic_info TYPE_NON_FATAL...\n"); /* * Step 1: Write the host buffer parameters in the MPI Fatal and * Non-Fatal Error Dump Capture Table.This is the buffer @@ -581,24 +569,24 @@ static void read_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version = pm8001_mr32(address, MAIN_MPI_INACTIVE_FW_VERSION); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "Main cfg table: sign:%x interface rev:%x fw_rev:%x\n", - pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature, - pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev, - pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev)); - - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "table offset: gst:%x iq:%x oq:%x int vec:%x phy attr:%x\n", - pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset, - pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset, - pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset, - pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset, - pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset)); - - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "Main cfg table; ila rev:%x Inactive fw rev:%x\n", - pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version, - pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version)); + pm8001_dbg(pm8001_ha, DEV, + "Main cfg table: sign:%x interface rev:%x fw_rev:%x\n", + pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev); + + pm8001_dbg(pm8001_ha, DEV, + "table offset: gst:%x iq:%x oq:%x int vec:%x phy attr:%x\n", + pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset); + + pm8001_dbg(pm8001_ha, DEV, + "Main cfg table; ila rev:%x Inactive fw rev:%x\n", + pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version); } /** @@ -808,10 +796,10 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha) pm8001_ha->inbnd_q_tbl[i].producer_idx = 0; pm8001_ha->inbnd_q_tbl[i].consumer_index = 0; - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "IQ %d pi_bar 0x%x pi_offset 0x%x\n", i, - pm8001_ha->inbnd_q_tbl[i].pi_pci_bar, - pm8001_ha->inbnd_q_tbl[i].pi_offset)); + pm8001_dbg(pm8001_ha, DEV, + "IQ %d pi_bar 0x%x pi_offset 0x%x\n", i, + pm8001_ha->inbnd_q_tbl[i].pi_pci_bar, + pm8001_ha->inbnd_q_tbl[i].pi_offset); } for (i = 0; i < pm8001_ha->max_q_num; i++) { pm8001_ha->outbnd_q_tbl[i].element_size_cnt = @@ -841,10 +829,10 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha) pm8001_ha->outbnd_q_tbl[i].consumer_idx = 0; pm8001_ha->outbnd_q_tbl[i].producer_index = 0; - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "OQ %d ci_bar 0x%x ci_offset 0x%x\n", i, - pm8001_ha->outbnd_q_tbl[i].ci_pci_bar, - pm8001_ha->outbnd_q_tbl[i].ci_offset)); + pm8001_dbg(pm8001_ha, DEV, + "OQ %d ci_bar 0x%x ci_offset 0x%x\n", i, + pm8001_ha->outbnd_q_tbl[i].ci_pci_bar, + pm8001_ha->outbnd_q_tbl[i].ci_offset); } } @@ -878,9 +866,9 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) ((pm8001_ha->max_q_num - 1) << 8); pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT, pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "Updated Fatal error interrupt vector 0x%x\n", - pm8001_mr32(address, MAIN_FATAL_ERROR_INTERRUPT))); + pm8001_dbg(pm8001_ha, DEV, + "Updated Fatal error interrupt vector 0x%x\n", + pm8001_mr32(address, MAIN_FATAL_ERROR_INTERRUPT)); pm8001_mw32(address, MAIN_EVENT_CRC_CHECK, pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump); @@ -891,9 +879,9 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping |= 0x20000000; pm8001_mw32(address, MAIN_GPIO_LED_FLAGS_OFFSET, pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "Programming DW 0x21 in main cfg table with 0x%x\n", - pm8001_mr32(address, MAIN_GPIO_LED_FLAGS_OFFSET))); + pm8001_dbg(pm8001_ha, DEV, + "Programming DW 0x21 in main cfg table with 0x%x\n", + pm8001_mr32(address, MAIN_GPIO_LED_FLAGS_OFFSET)); pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER, pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); @@ -934,20 +922,20 @@ static void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha, pm8001_mw32(address, offset + IB_CI_BASE_ADDR_LO_OFFSET, pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "IQ %d: Element pri size 0x%x\n", - number, - pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt)); + pm8001_dbg(pm8001_ha, DEV, + "IQ %d: Element pri size 0x%x\n", + number, + pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "IQ upr base addr 0x%x IQ lwr base addr 0x%x\n", - pm8001_ha->inbnd_q_tbl[number].upper_base_addr, - pm8001_ha->inbnd_q_tbl[number].lower_base_addr)); + pm8001_dbg(pm8001_ha, DEV, + "IQ upr base addr 0x%x IQ lwr base addr 0x%x\n", + pm8001_ha->inbnd_q_tbl[number].upper_base_addr, + pm8001_ha->inbnd_q_tbl[number].lower_base_addr); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "CI upper base addr 0x%x CI lower base addr 0x%x\n", - pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr, - pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr)); + pm8001_dbg(pm8001_ha, DEV, + "CI upper base addr 0x%x CI lower base addr 0x%x\n", + pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr, + pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr); } /** @@ -973,20 +961,20 @@ static void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, pm8001_mw32(address, offset + OB_INTERRUPT_COALES_OFFSET, pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "OQ %d: Element pri size 0x%x\n", - number, - pm8001_ha->outbnd_q_tbl[number].element_size_cnt)); + pm8001_dbg(pm8001_ha, DEV, + "OQ %d: Element pri size 0x%x\n", + number, + pm8001_ha->outbnd_q_tbl[number].element_size_cnt); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "OQ upr base addr 0x%x OQ lwr base addr 0x%x\n", - pm8001_ha->outbnd_q_tbl[number].upper_base_addr, - pm8001_ha->outbnd_q_tbl[number].lower_base_addr)); + pm8001_dbg(pm8001_ha, DEV, + "OQ upr base addr 0x%x OQ lwr base addr 0x%x\n", + pm8001_ha->outbnd_q_tbl[number].upper_base_addr, + pm8001_ha->outbnd_q_tbl[number].lower_base_addr); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "PI upper base addr 0x%x PI lower base addr 0x%x\n", - pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr, - pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr)); + pm8001_dbg(pm8001_ha, DEV, + "PI upper base addr 0x%x PI lower base addr 0x%x\n", + pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr, + pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr); } /** @@ -1016,8 +1004,9 @@ static int mpi_init_check(struct pm8001_hba_info *pm8001_ha) if (!max_wait_count) { /* additional check */ - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "Inb doorbell clear not toggled[value:%x]\n", value)); + pm8001_dbg(pm8001_ha, FAIL, + "Inb doorbell clear not toggled[value:%x]\n", + value); return -EBUSY; } /* check the MPI-State for initialization upto 100ms*/ @@ -1042,6 +1031,7 @@ static int mpi_init_check(struct pm8001_hba_info *pm8001_ha) /** * check_fw_ready - The LLDD check if the FW is ready, if not, return error. + * This function sleeps hence it must not be used in atomic context. * @pm8001_ha: our hba card information */ static int check_fw_ready(struct pm8001_hba_info *pm8001_ha) @@ -1052,73 +1042,73 @@ static int check_fw_ready(struct pm8001_hba_info *pm8001_ha) int ret = 0; /* reset / PCIe ready */ - max_wait_time = max_wait_count = 100 * 1000; /* 100 milli sec */ + max_wait_time = max_wait_count = 5; /* 100 milli sec */ do { - udelay(1); + msleep(FW_READY_INTERVAL); value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); } while ((value == 0xFFFFFFFF) && (--max_wait_count)); /* check ila status */ - max_wait_time = max_wait_count = 1000 * 1000; /* 1000 milli sec */ + max_wait_time = max_wait_count = 50; /* 1000 milli sec */ do { - udelay(1); + msleep(FW_READY_INTERVAL); value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); } while (((value & SCRATCH_PAD_ILA_READY) != SCRATCH_PAD_ILA_READY) && (--max_wait_count)); if (!max_wait_count) ret = -1; else { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" ila ready status in %d millisec\n", - (max_wait_time - max_wait_count))); + pm8001_dbg(pm8001_ha, MSG, + " ila ready status in %d millisec\n", + (max_wait_time - max_wait_count)); } /* check RAAE status */ - max_wait_time = max_wait_count = 1800 * 1000; /* 1800 milli sec */ + max_wait_time = max_wait_count = 90; /* 1800 milli sec */ do { - udelay(1); + msleep(FW_READY_INTERVAL); value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); } while (((value & SCRATCH_PAD_RAAE_READY) != SCRATCH_PAD_RAAE_READY) && (--max_wait_count)); if (!max_wait_count) ret = -1; else { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" raae ready status in %d millisec\n", - (max_wait_time - max_wait_count))); + pm8001_dbg(pm8001_ha, MSG, + " raae ready status in %d millisec\n", + (max_wait_time - max_wait_count)); } /* check iop0 status */ - max_wait_time = max_wait_count = 600 * 1000; /* 600 milli sec */ + max_wait_time = max_wait_count = 30; /* 600 milli sec */ do { - udelay(1); + msleep(FW_READY_INTERVAL); value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); } while (((value & SCRATCH_PAD_IOP0_READY) != SCRATCH_PAD_IOP0_READY) && (--max_wait_count)); if (!max_wait_count) ret = -1; else { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" iop0 ready status in %d millisec\n", - (max_wait_time - max_wait_count))); + pm8001_dbg(pm8001_ha, MSG, + " iop0 ready status in %d millisec\n", + (max_wait_time - max_wait_count)); } /* check iop1 status only for 16 port controllers */ if ((pm8001_ha->chip_id != chip_8008) && (pm8001_ha->chip_id != chip_8009)) { /* 200 milli sec */ - max_wait_time = max_wait_count = 200 * 1000; + max_wait_time = max_wait_count = 10; do { - udelay(1); + msleep(FW_READY_INTERVAL); value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); } while (((value & SCRATCH_PAD_IOP1_READY) != SCRATCH_PAD_IOP1_READY) && (--max_wait_count)); if (!max_wait_count) ret = -1; else { - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "iop1 ready status in %d millisec\n", - (max_wait_time - max_wait_count))); + pm8001_dbg(pm8001_ha, MSG, + "iop1 ready status in %d millisec\n", + (max_wait_time - max_wait_count)); } } @@ -1136,13 +1126,11 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0); offset = value & 0x03FFFFFF; /* scratch pad 0 TBL address */ - PM8001_DEV_DBG(pm8001_ha, - pm8001_printk("Scratchpad 0 Offset: 0x%x value 0x%x\n", - offset, value)); + pm8001_dbg(pm8001_ha, DEV, "Scratchpad 0 Offset: 0x%x value 0x%x\n", + offset, value); pcilogic = (value & 0xFC000000) >> 26; pcibar = get_pci_bar_index(pcilogic); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Scratchpad 0 PCI BAR: %d\n", pcibar)); + pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 PCI BAR: %d\n", pcibar); pm8001_ha->main_cfg_tbl_addr = base_addr = pm8001_ha->io_mem[pcibar].memvirtaddr + offset; pm8001_ha->general_stat_tbl_addr = @@ -1164,33 +1152,25 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0xA0) & 0xFFFFFF); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GST OFFSET 0x%x\n", - pm8001_cr32(pm8001_ha, pcibar, offset + 0x18))); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("INBND OFFSET 0x%x\n", - pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C))); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("OBND OFFSET 0x%x\n", - pm8001_cr32(pm8001_ha, pcibar, offset + 0x20))); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("IVT OFFSET 0x%x\n", - pm8001_cr32(pm8001_ha, pcibar, offset + 0x8C))); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PSPA OFFSET 0x%x\n", - pm8001_cr32(pm8001_ha, pcibar, offset + 0x90))); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("addr - main cfg %p general status %p\n", - pm8001_ha->main_cfg_tbl_addr, - pm8001_ha->general_stat_tbl_addr)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("addr - inbnd %p obnd %p\n", - pm8001_ha->inbnd_q_tbl_addr, - pm8001_ha->outbnd_q_tbl_addr)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("addr - pspa %p ivt %p\n", - pm8001_ha->pspa_q_tbl_addr, - pm8001_ha->ivt_tbl_addr)); + pm8001_dbg(pm8001_ha, INIT, "GST OFFSET 0x%x\n", + pm8001_cr32(pm8001_ha, pcibar, offset + 0x18)); + pm8001_dbg(pm8001_ha, INIT, "INBND OFFSET 0x%x\n", + pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C)); + pm8001_dbg(pm8001_ha, INIT, "OBND OFFSET 0x%x\n", + pm8001_cr32(pm8001_ha, pcibar, offset + 0x20)); + pm8001_dbg(pm8001_ha, INIT, "IVT OFFSET 0x%x\n", + pm8001_cr32(pm8001_ha, pcibar, offset + 0x8C)); + pm8001_dbg(pm8001_ha, INIT, "PSPA OFFSET 0x%x\n", + pm8001_cr32(pm8001_ha, pcibar, offset + 0x90)); + pm8001_dbg(pm8001_ha, INIT, "addr - main cfg %p general status %p\n", + pm8001_ha->main_cfg_tbl_addr, + pm8001_ha->general_stat_tbl_addr); + pm8001_dbg(pm8001_ha, INIT, "addr - inbnd %p obnd %p\n", + pm8001_ha->inbnd_q_tbl_addr, + pm8001_ha->outbnd_q_tbl_addr); + pm8001_dbg(pm8001_ha, INIT, "addr - pspa %p ivt %p\n", + pm8001_ha->pspa_q_tbl_addr, + pm8001_ha->ivt_tbl_addr); } /** @@ -1224,9 +1204,9 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) (THERMAL_ENABLE << 8) | page_code; payload.cfg_pg[1] = (LTEMPHIL << 24) | (RTEMPHIL << 8); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n", - payload.cfg_pg[0], payload.cfg_pg[1])); + pm8001_dbg(pm8001_ha, DEV, + "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n", + payload.cfg_pg[0], payload.cfg_pg[1]); rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, sizeof(payload), 0); @@ -1281,32 +1261,24 @@ pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha) | SAS_COPNRJT_RTRY_THR; SASConfigPage.MAX_AIP = SAS_MAX_AIP; - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SASConfigPage.pageCode " - "0x%08x\n", SASConfigPage.pageCode)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SASConfigPage.MST_MSI " - " 0x%08x\n", SASConfigPage.MST_MSI)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SASConfigPage.STP_SSP_MCT_TMO " - " 0x%08x\n", SASConfigPage.STP_SSP_MCT_TMO)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SASConfigPage.STP_FRM_TMO " - " 0x%08x\n", SASConfigPage.STP_FRM_TMO)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SASConfigPage.STP_IDLE_TMO " - " 0x%08x\n", SASConfigPage.STP_IDLE_TMO)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SASConfigPage.OPNRJT_RTRY_INTVL " - " 0x%08x\n", SASConfigPage.OPNRJT_RTRY_INTVL)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO " - " 0x%08x\n", SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR " - " 0x%08x\n", SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR)); - PM8001_INIT_DBG(pm8001_ha, pm8001_printk("SASConfigPage.MAX_AIP " - " 0x%08x\n", SASConfigPage.MAX_AIP)); + pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.pageCode 0x%08x\n", + SASConfigPage.pageCode); + pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MST_MSI 0x%08x\n", + SASConfigPage.MST_MSI); + pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_SSP_MCT_TMO 0x%08x\n", + SASConfigPage.STP_SSP_MCT_TMO); + pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_FRM_TMO 0x%08x\n", + SASConfigPage.STP_FRM_TMO); + pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_IDLE_TMO 0x%08x\n", + SASConfigPage.STP_IDLE_TMO); + pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.OPNRJT_RTRY_INTVL 0x%08x\n", + SASConfigPage.OPNRJT_RTRY_INTVL); + pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO 0x%08x\n", + SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO); + pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR 0x%08x\n", + SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR); + pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MAX_AIP 0x%08x\n", + SASConfigPage.MAX_AIP); memcpy(&payload.cfg_pg, &SASConfigPage, sizeof(SASProtocolTimerConfig_t)); @@ -1346,18 +1318,18 @@ pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha) SCRATCH_PAD3_SMB_ENABLED) pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB; pm8001_ha->encrypt_info.status = 0; - PM8001_INIT_DBG(pm8001_ha, pm8001_printk( - "Encryption: SCRATCH_PAD3_ENC_READY 0x%08X." - "Cipher mode 0x%x Sec mode 0x%x status 0x%x\n", - scratch3_value, pm8001_ha->encrypt_info.cipher_mode, - pm8001_ha->encrypt_info.sec_mode, - pm8001_ha->encrypt_info.status)); + pm8001_dbg(pm8001_ha, INIT, + "Encryption: SCRATCH_PAD3_ENC_READY 0x%08X.Cipher mode 0x%x Sec mode 0x%x status 0x%x\n", + scratch3_value, + pm8001_ha->encrypt_info.cipher_mode, + pm8001_ha->encrypt_info.sec_mode, + pm8001_ha->encrypt_info.status); ret = 0; } else if ((scratch3_value & SCRATCH_PAD3_ENC_READY) == SCRATCH_PAD3_ENC_DISABLED) { - PM8001_INIT_DBG(pm8001_ha, pm8001_printk( - "Encryption: SCRATCH_PAD3_ENC_DISABLED 0x%08X\n", - scratch3_value)); + pm8001_dbg(pm8001_ha, INIT, + "Encryption: SCRATCH_PAD3_ENC_DISABLED 0x%08X\n", + scratch3_value); pm8001_ha->encrypt_info.status = 0xFFFFFFFF; pm8001_ha->encrypt_info.cipher_mode = 0; pm8001_ha->encrypt_info.sec_mode = 0; @@ -1377,12 +1349,12 @@ pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha) if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == SCRATCH_PAD3_SMB_ENABLED) pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB; - PM8001_INIT_DBG(pm8001_ha, pm8001_printk( - "Encryption: SCRATCH_PAD3_DIS_ERR 0x%08X." - "Cipher mode 0x%x sec mode 0x%x status 0x%x\n", - scratch3_value, pm8001_ha->encrypt_info.cipher_mode, - pm8001_ha->encrypt_info.sec_mode, - pm8001_ha->encrypt_info.status)); + pm8001_dbg(pm8001_ha, INIT, + "Encryption: SCRATCH_PAD3_DIS_ERR 0x%08X.Cipher mode 0x%x sec mode 0x%x status 0x%x\n", + scratch3_value, + pm8001_ha->encrypt_info.cipher_mode, + pm8001_ha->encrypt_info.sec_mode, + pm8001_ha->encrypt_info.status); } else if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) == SCRATCH_PAD3_ENC_ENA_ERR) { @@ -1400,12 +1372,12 @@ pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha) SCRATCH_PAD3_SMB_ENABLED) pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB; - PM8001_INIT_DBG(pm8001_ha, pm8001_printk( - "Encryption: SCRATCH_PAD3_ENA_ERR 0x%08X." - "Cipher mode 0x%x sec mode 0x%x status 0x%x\n", - scratch3_value, pm8001_ha->encrypt_info.cipher_mode, - pm8001_ha->encrypt_info.sec_mode, - pm8001_ha->encrypt_info.status)); + pm8001_dbg(pm8001_ha, INIT, + "Encryption: SCRATCH_PAD3_ENA_ERR 0x%08X.Cipher mode 0x%x sec mode 0x%x status 0x%x\n", + scratch3_value, + pm8001_ha->encrypt_info.cipher_mode, + pm8001_ha->encrypt_info.sec_mode, + pm8001_ha->encrypt_info.status); } return ret; } @@ -1435,9 +1407,9 @@ static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha) payload.new_curidx_ksop = ((1 << 24) | (1 << 16) | (1 << 8) | KEK_MGMT_SUBOP_KEYCARDUPDATE); - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "Saving Encryption info to flash. payload 0x%x\n", - payload.new_curidx_ksop)); + pm8001_dbg(pm8001_ha, DEV, + "Saving Encryption info to flash. payload 0x%x\n", + payload.new_curidx_ksop); rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, sizeof(payload), 0); @@ -1458,8 +1430,7 @@ static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha) /* check the firmware status */ if (-1 == check_fw_ready(pm8001_ha)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Firmware is not ready!\n")); + pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n"); return -EBUSY; } @@ -1483,8 +1454,7 @@ static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha) } /* notify firmware update finished and check initialization status */ if (0 == mpi_init_check(pm8001_ha)) { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MPI initialize successful!\n")); + pm8001_dbg(pm8001_ha, INIT, "MPI initialize successful!\n"); } else return -EBUSY; @@ -1493,16 +1463,13 @@ static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha) /* Check for encryption */ if (pm8001_ha->chip->encrypt) { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Checking for encryption\n")); + pm8001_dbg(pm8001_ha, INIT, "Checking for encryption\n"); ret = pm80xx_get_encrypt_info(pm8001_ha); if (ret == -1) { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Encryption error !!\n")); + pm8001_dbg(pm8001_ha, INIT, "Encryption error !!\n"); if (pm8001_ha->encrypt_info.status == 0x81) { - PM8001_INIT_DBG(pm8001_ha, pm8001_printk( - "Encryption enabled with error." - "Saving encryption key to flash\n")); + pm8001_dbg(pm8001_ha, INIT, + "Encryption enabled with error.Saving encryption key to flash\n"); pm80xx_encrypt_update(pm8001_ha); } } @@ -1533,8 +1500,7 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) } while ((value != 0) && (--max_wait_count)); if (!max_wait_count) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TIMEOUT:IBDB value/=%x\n", value)); + pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:IBDB value/=%x\n", value); return -1; } @@ -1551,9 +1517,8 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) break; } while (--max_wait_count); if (!max_wait_count) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk(" TIME OUT MPI State = 0x%x\n", - gst_len_mpistate & GST_MPI_STATE_MASK)); + pm8001_dbg(pm8001_ha, FAIL, " TIME OUT MPI State = 0x%x\n", + gst_len_mpistate & GST_MPI_STATE_MASK); return -1; } @@ -1581,9 +1546,9 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) u32 r1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); u32 r2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2); u32 r3 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "MPI state is not ready scratch: %x:%x:%x:%x\n", - r0, r1, r2, r3)); + pm8001_dbg(pm8001_ha, FAIL, + "MPI state is not ready scratch: %x:%x:%x:%x\n", + r0, r1, r2, r3); /* if things aren't ready but the bootloader is ok then * try the reset anyway. */ @@ -1593,25 +1558,25 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) } /* checked for reset register normal state; 0x0 */ regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("reset register before write : 0x%x\n", regval)); + pm8001_dbg(pm8001_ha, INIT, "reset register before write : 0x%x\n", + regval); pm8001_cw32(pm8001_ha, 0, SPC_REG_SOFT_RESET, SPCv_NORMAL_RESET_VALUE); msleep(500); regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("reset register after write 0x%x\n", regval)); + pm8001_dbg(pm8001_ha, INIT, "reset register after write 0x%x\n", + regval); if ((regval & SPCv_SOFT_RESET_READ_MASK) == SPCv_SOFT_RESET_NORMAL_RESET_OCCURED) { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" soft reset successful [regval: 0x%x]\n", - regval)); + pm8001_dbg(pm8001_ha, MSG, + " soft reset successful [regval: 0x%x]\n", + regval); } else { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" soft reset failed [regval: 0x%x]\n", - regval)); + pm8001_dbg(pm8001_ha, MSG, + " soft reset failed [regval: 0x%x]\n", + regval); /* check bootloader is successfully executed or in HDA mode */ bootloader_state = @@ -1619,28 +1584,27 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) SCRATCH_PAD1_BOOTSTATE_MASK; if (bootloader_state == SCRATCH_PAD1_BOOTSTATE_HDA_SEEPROM) { - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "Bootloader state - HDA mode SEEPROM\n")); + pm8001_dbg(pm8001_ha, MSG, + "Bootloader state - HDA mode SEEPROM\n"); } else if (bootloader_state == SCRATCH_PAD1_BOOTSTATE_HDA_BOOTSTRAP) { - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "Bootloader state - HDA mode Bootstrap Pin\n")); + pm8001_dbg(pm8001_ha, MSG, + "Bootloader state - HDA mode Bootstrap Pin\n"); } else if (bootloader_state == SCRATCH_PAD1_BOOTSTATE_HDA_SOFTRESET) { - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "Bootloader state - HDA mode soft reset\n")); + pm8001_dbg(pm8001_ha, MSG, + "Bootloader state - HDA mode soft reset\n"); } else if (bootloader_state == SCRATCH_PAD1_BOOTSTATE_CRIT_ERROR) { - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "Bootloader state-HDA mode critical error\n")); + pm8001_dbg(pm8001_ha, MSG, + "Bootloader state-HDA mode critical error\n"); } return -EBUSY; } /* check the firmware status after reset */ if (-1 == check_fw_ready(pm8001_ha)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Firmware is not ready!\n")); + pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n"); /* check iButton feature support for motherboard controller */ if (pm8001_ha->pdev->subsystem_vendor != PCI_VENDOR_ID_ADAPTEC2 && @@ -1652,21 +1616,18 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) ibutton1 = pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_7); if (!ibutton0 && !ibutton1) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("iButton Feature is" - " not Available!!!\n")); + pm8001_dbg(pm8001_ha, FAIL, + "iButton Feature is not Available!!!\n"); return -EBUSY; } if (ibutton0 == 0xdeadbeef && ibutton1 == 0xdeadbeef) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("CRC Check for iButton" - " Feature Failed!!!\n")); + pm8001_dbg(pm8001_ha, FAIL, + "CRC Check for iButton Feature Failed!!!\n"); return -EBUSY; } } } - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SPCv soft reset Complete\n")); + pm8001_dbg(pm8001_ha, INIT, "SPCv soft reset Complete\n"); return 0; } @@ -1674,13 +1635,11 @@ static void pm80xx_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) { u32 i; - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("chip reset start\n")); + pm8001_dbg(pm8001_ha, INIT, "chip reset start\n"); /* do SPCv chip reset. */ pm8001_cw32(pm8001_ha, 0, SPC_REG_SOFT_RESET, 0x11); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SPC soft reset Complete\n")); + pm8001_dbg(pm8001_ha, INIT, "SPC soft reset Complete\n"); /* Check this ..whether delay is required or no */ /* delay 10 usec */ @@ -1692,8 +1651,7 @@ static void pm80xx_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) mdelay(1); } while ((--i) != 0); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("chip reset finished\n")); + pm8001_dbg(pm8001_ha, INIT, "chip reset finished\n"); } /** @@ -1769,15 +1727,14 @@ static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha, int ret; if (!pm8001_ha_dev) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("dev is null\n")); + pm8001_dbg(pm8001_ha, FAIL, "dev is null\n"); return; } task = sas_alloc_slow_task(GFP_ATOMIC); if (!task) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("cannot " - "allocate task\n")); + pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task\n"); return; } @@ -1803,8 +1760,7 @@ static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha, ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, sizeof(task_abort), 0); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Executing abort task end\n")); + pm8001_dbg(pm8001_ha, FAIL, "Executing abort task end\n"); if (ret) { sas_free_task(task); pm8001_tag_free(pm8001_ha, ccb_tag); @@ -1827,8 +1783,7 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, task = sas_alloc_slow_task(GFP_ATOMIC); if (!task) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("cannot allocate task !!!\n")); + pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task !!!\n"); return; } task->task_done = pm8001_task_done; @@ -1836,8 +1791,7 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, res = pm8001_tag_alloc(pm8001_ha, &ccb_tag); if (res) { sas_free_task(task); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("cannot allocate tag !!!\n")); + pm8001_dbg(pm8001_ha, FAIL, "cannot allocate tag !!!\n"); return; } @@ -1848,8 +1802,8 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, if (!dev) { sas_free_task(task); pm8001_tag_free(pm8001_ha, ccb_tag); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Domain device cannot be allocated\n")); + pm8001_dbg(pm8001_ha, FAIL, + "Domain device cannot be allocated\n"); return; } @@ -1882,7 +1836,7 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, sizeof(sata_cmd), 0); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("Executing read log end\n")); + pm8001_dbg(pm8001_ha, FAIL, "Executing read log end\n"); if (res) { sas_free_task(task); pm8001_tag_free(pm8001_ha, ccb_tag); @@ -1928,27 +1882,24 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) t = ccb->task; if (status && status != IO_UNDERFLOW) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("sas IO status 0x%x\n", status)); + pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", status); if (unlikely(!t || !t->lldd_task || !t->dev)) return; ts = &t->task_status; - PM8001_DEV_DBG(pm8001_ha, pm8001_printk( - "tag::0x%x, status::0x%x task::0x%p\n", tag, status, t)); + pm8001_dbg(pm8001_ha, DEV, + "tag::0x%x, status::0x%x task::0x%p\n", tag, status, t); /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SAS Address of IO Failure Drive" - ":%016llx", SAS_ADDR(t->dev->sas_addr))); + pm8001_dbg(pm8001_ha, FAIL, "SAS Address of IO Failure Drive:%016llx\n", + SAS_ADDR(t->dev->sas_addr)); switch (status) { case IO_SUCCESS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_SUCCESS ,param = 0x%x\n", - param)); + pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS ,param = 0x%x\n", + param); if (param == 0) { ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_GOOD; @@ -1960,73 +1911,83 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) sas_ssp_task_response(pm8001_ha->dev, t, iu); } if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ABORTED IOMB Tag\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_ABORTED_TASK; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_UNDERFLOW: /* SSP Completion with error */ - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_UNDERFLOW ,param = 0x%x\n", - param)); + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW ,param = 0x%x\n", + param); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_UNDERRUN; ts->residual = param; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_NO_DEVICE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_NO_DEVICE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; /* Force the midlayer to retry */ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_INVALID_SSP_RSP_FRAME: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_INVALID_SSP_RSP_FRAME\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_INVALID_SSP_RSP_FRAME\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_EPROTO; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: @@ -2034,8 +1995,7 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; @@ -2045,67 +2005,78 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_DMA: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_DMA\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_OFFSET_MISMATCH: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_PORT_IN_RESET: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_PORT_IN_RESET\n")); + pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_DS_NON_OPERATIONAL: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_NON_OPERATIONAL\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; if (!t->uldd_task) @@ -2114,51 +2085,55 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) IO_DS_NON_OPERATIONAL); break; case IO_DS_IN_RECOVERY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_RECOVERY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_TM_TAG_NOT_FOUND: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_TM_TAG_NOT_FOUND\n")); + pm8001_dbg(pm8001_ha, IO, "IO_TM_TAG_NOT_FOUND\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_SSP_EXT_IU_ZERO_LEN_ERROR: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_SSP_EXT_IU_ZERO_LEN_ERROR\n")); + pm8001_dbg(pm8001_ha, IO, "IO_SSP_EXT_IU_ZERO_LEN_ERROR\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", status)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; } - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("scsi_status = 0x%x\n ", - psspPayload->ssp_resp_iu.status)); + pm8001_dbg(pm8001_ha, IO, "scsi_status = 0x%x\n ", + psspPayload->ssp_resp_iu.status); spin_lock_irqsave(&t->task_state_lock, flags); t->task_state_flags &= ~SAS_TASK_STATE_PENDING; t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "task 0x%p done with io_status 0x%x resp 0x%x " - "stat 0x%x but aborted by upper layer!\n", - t, status, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, + "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, status, ts->resp, ts->stat); if (t->slow_task) complete(&t->slow_task->completion); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); @@ -2188,52 +2163,47 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) t = ccb->task; pm8001_dev = ccb->device; if (event) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("sas IO status 0x%x\n", event)); + pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", event); if (unlikely(!t || !t->lldd_task || !t->dev)) return; ts = &t->task_status; - PM8001_IOERR_DBG(pm8001_ha, - pm8001_printk("port_id:0x%x, tag:0x%x, event:0x%x\n", - port_id, tag, event)); + pm8001_dbg(pm8001_ha, IOERR, "port_id:0x%x, tag:0x%x, event:0x%x\n", + port_id, tag, event); switch (event) { case IO_OVERFLOW: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n");) + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; ts->residual = 0; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK); return; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_EPROTO; break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; @@ -2244,8 +2214,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; @@ -2255,94 +2224,86 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; break; case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_XFER_ERROR_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT); return; case IO_XFER_ERROR_UNEXPECTED_PHASE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_XFER_RDY_OVERRUN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_OVERRUN\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_OFFSET_MISMATCH: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_INTERNAL_CRC_ERROR: - PM8001_IOERR_DBG(pm8001_ha, - pm8001_printk("IO_XFR_ERROR_INTERNAL_CRC_ERROR\n")); + pm8001_dbg(pm8001_ha, IOERR, + "IO_XFR_ERROR_INTERNAL_CRC_ERROR\n"); /* TBC: used default set values */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_CMD_FRAME_ISSUED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_CMD_FRAME_ISSUED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n"); return; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", event)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", event); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; @@ -2354,10 +2315,9 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "task 0x%p done with event 0x%x resp 0x%x " - "stat 0x%x but aborted by upper layer!\n", - t, event, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, + "task 0x%p done with event 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, event, ts->resp, ts->stat); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); @@ -2392,8 +2352,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) tag = le32_to_cpu(psataPayload->tag); if (!tag) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("tag null\n")); + pm8001_dbg(pm8001_ha, FAIL, "tag null\n"); return; } ccb = &pm8001_ha->ccb_info[tag]; @@ -2402,8 +2361,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) t = ccb->task; pm8001_dev = ccb->device; } else { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("ccb null\n")); + pm8001_dbg(pm8001_ha, FAIL, "ccb null\n"); return; } @@ -2411,29 +2369,26 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) if (t->dev && (t->dev->lldd_dev)) pm8001_dev = t->dev->lldd_dev; } else { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task null\n")); + pm8001_dbg(pm8001_ha, FAIL, "task null\n"); return; } if ((pm8001_dev && !(pm8001_dev->id & NCQ_READ_LOG_FLAG)) && unlikely(!t || !t->lldd_task || !t->dev)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task or dev null\n")); + pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n"); return; } ts = &t->task_status; if (!ts) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("ts null\n")); + pm8001_dbg(pm8001_ha, FAIL, "ts null\n"); return; } if (unlikely(status)) - PM8001_IOERR_DBG(pm8001_ha, pm8001_printk( - "status:0x%x, tag:0x%x, task::0x%p\n", - status, tag, t)); + pm8001_dbg(pm8001_ha, IOERR, + "status:0x%x, tag:0x%x, task::0x%p\n", + status, tag, t); /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && @@ -2465,20 +2420,20 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) & 0xff000000)) + pm8001_dev->attached_phy + 0x10); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SAS Address of IO Failure Drive:" - "%08x%08x", temp_sata_addr_hi, - temp_sata_addr_low)); + pm8001_dbg(pm8001_ha, FAIL, + "SAS Address of IO Failure Drive:%08x%08x\n", + temp_sata_addr_hi, + temp_sata_addr_low); } else { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SAS Address of IO Failure Drive:" - "%016llx", SAS_ADDR(t->dev->sas_addr))); + pm8001_dbg(pm8001_ha, FAIL, + "SAS Address of IO Failure Drive:%016llx\n", + SAS_ADDR(t->dev->sas_addr)); } } switch (status) { case IO_SUCCESS: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n"); if (param == 0) { ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_GOOD; @@ -2500,94 +2455,100 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_PROTO_RESPONSE; ts->residual = param; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("SAS_PROTO_RESPONSE len = %d\n", - param)); + pm8001_dbg(pm8001_ha, IO, + "SAS_PROTO_RESPONSE len = %d\n", + param); sata_resp = &psataPayload->sata_resp[0]; resp = (struct ata_task_resp *)ts->buf; if (t->ata_task.dma_xfer == 0 && t->data_dir == DMA_FROM_DEVICE) { len = sizeof(struct pio_setup_fis); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("PIO read len = %d\n", len)); + pm8001_dbg(pm8001_ha, IO, + "PIO read len = %d\n", len); } else if (t->ata_task.use_ncq) { len = sizeof(struct set_dev_bits_fis); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("FPDMA len = %d\n", len)); + pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n", + len); } else { len = sizeof(struct dev_to_host_fis); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("other len = %d\n", len)); + pm8001_dbg(pm8001_ha, IO, "other len = %d\n", + len); } if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { resp->frame_len = len; memcpy(&resp->ending_fis[0], sata_resp, len); ts->buf_valid_size = sizeof(*resp); } else - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("response too large\n")); + pm8001_dbg(pm8001_ha, IO, + "response too large\n"); } if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ABORTED IOMB Tag\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_ABORTED_TASK; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; /* following cases are to do cases */ case IO_UNDERFLOW: /* SATA Completion with error */ - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_UNDERFLOW param = %d\n", param)); + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW param = %d\n", param); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_UNDERRUN; ts->residual = param; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_NO_DEVICE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_NO_DEVICE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_INTERRUPTED; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_EPROTO; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: @@ -2595,8 +2556,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2610,8 +2570,8 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; @@ -2626,15 +2586,17 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2648,57 +2610,65 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_DMA: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_DMA\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_ABORTED_TASK; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_SATA_LINK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_SATA_LINK_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_SATA_LINK_TIMEOUT\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_DEV_NO_RESPONSE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_REJECTED_NCQ_MODE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_REJECTED_NCQ_MODE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_UNDERRUN; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_PORT_IN_RESET: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_PORT_IN_RESET\n")); + pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_DS_NON_OPERATIONAL: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_NON_OPERATIONAL\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2711,14 +2681,14 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_DS_IN_RECOVERY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_RECOVERY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; case IO_DS_IN_ERROR: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_ERROR\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_ERROR\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2731,18 +2701,21 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", status)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; + if (pm8001_dev) + atomic_dec(&pm8001_dev->running_req); break; } spin_lock_irqsave(&t->task_state_lock, flags); @@ -2751,10 +2724,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task 0x%p done with io_status 0x%x" - " resp 0x%x stat 0x%x but aborted by upper layer!\n", - t, status, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, + "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, status, ts->resp, ts->stat); if (t->slow_task) complete(&t->slow_task->completion); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); @@ -2785,13 +2757,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) t = ccb->task; pm8001_dev = ccb->device; } else { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("No CCB !!!. returning\n")); + pm8001_dbg(pm8001_ha, FAIL, "No CCB !!!. returning\n"); return; } if (event) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SATA EVENT 0x%x\n", event)); + pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event); /* Check if this is NCQ error */ if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) { @@ -2804,54 +2774,49 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) } if (unlikely(!t || !t->lldd_task || !t->dev)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task or dev null\n")); + pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n"); return; } ts = &t->task_status; - PM8001_IOERR_DBG(pm8001_ha, - pm8001_printk("port_id:0x%x, tag:0x%x, event:0x%x\n", - port_id, tag, event)); + pm8001_dbg(pm8001_ha, IOERR, "port_id:0x%x, tag:0x%x, event:0x%x\n", + port_id, tag, event); switch (event) { case IO_OVERFLOW: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n")); + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; ts->residual = 0; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_INTERRUPTED; break; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_EPROTO; break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; @@ -2862,8 +2827,8 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, FAIL, + "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_DEV_NO_RESPONSE; if (!t->uldd_task) { @@ -2877,107 +2842,96 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) } break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; break; case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; break; case IO_XFER_ERROR_PEER_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PEER_ABORTED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PEER_ABORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_NAK_R_ERR; break; case IO_XFER_ERROR_REJECTED_NCQ_MODE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_REJECTED_NCQ_MODE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_UNDERRUN; break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_UNEXPECTED_PHASE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_XFER_RDY_OVERRUN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_OVERRUN\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_OFFSET_MISMATCH: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_CMD_FRAME_ISSUED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_CMD_FRAME_ISSUED\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n"); break; case IO_XFER_PIO_SETUP_ERROR: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_PIO_SETUP_ERROR\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_PIO_SETUP_ERROR\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_ERROR_INTERNAL_CRC_ERROR: - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("IO_XFR_ERROR_INTERNAL_CRC_ERROR\n")); + pm8001_dbg(pm8001_ha, FAIL, + "IO_XFR_ERROR_INTERNAL_CRC_ERROR\n"); /* TBC: used default set values */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; case IO_XFER_DMA_ACTIVATE_TIMEOUT: - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("IO_XFR_DMA_ACTIVATE_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, FAIL, "IO_XFR_DMA_ACTIVATE_TIMEOUT\n"); /* TBC: used default set values */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; break; default: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", event)); + pm8001_dbg(pm8001_ha, IO, "Unknown status 0x%x\n", event); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_TO; @@ -2989,10 +2943,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task 0x%p done with io_status 0x%x" - " resp 0x%x stat 0x%x but aborted by upper layer!\n", - t, event, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, + "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", + t, event, ts->resp, ts->stat); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); @@ -3025,94 +2978,87 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts = &t->task_status; pm8001_dev = ccb->device; if (status) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("smp IO status 0x%x\n", status)); + pm8001_dbg(pm8001_ha, FAIL, "smp IO status 0x%x\n", status); if (unlikely(!t || !t->lldd_task || !t->dev)) return; - PM8001_DEV_DBG(pm8001_ha, - pm8001_printk("tag::0x%x status::0x%x\n", tag, status)); + pm8001_dbg(pm8001_ha, DEV, "tag::0x%x status::0x%x\n", tag, status); switch (status) { case IO_SUCCESS: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_GOOD; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); if (pm8001_ha->smp_exp_mode == SMP_DIRECT) { - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("DIRECT RESPONSE Length:%d\n", - param)); + pm8001_dbg(pm8001_ha, IO, + "DIRECT RESPONSE Length:%d\n", + param); pdma_respaddr = (char *)(phys_to_virt(cpu_to_le64 ((u64)sg_dma_address (&t->smp_task.smp_resp)))); for (i = 0; i < param; i++) { *(pdma_respaddr+i) = psmpPayload->_r_a[i]; - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "SMP Byte%d DMA data 0x%x psmp 0x%x\n", - i, *(pdma_respaddr+i), - psmpPayload->_r_a[i])); + pm8001_dbg(pm8001_ha, IO, + "SMP Byte%d DMA data 0x%x psmp 0x%x\n", + i, *(pdma_respaddr + i), + psmpPayload->_r_a[i]); } } break; case IO_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ABORTED IOMB\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_ABORTED_TASK; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_OVERFLOW: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n")); + pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DATA_OVERRUN; ts->residual = 0; if (pm8001_dev) - pm8001_dev->running_req--; + atomic_dec(&pm8001_dev->running_req); break; case IO_NO_DEVICE: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_NO_DEVICE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_PHY_DOWN; break; case IO_ERROR_HW_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ERROR_HW_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ERROR_HW_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_BUSY; break; case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_BUSY; break; case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_BUSY; break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; break; case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; @@ -3123,8 +3069,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); + pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_UNKNOWN; @@ -3133,75 +3078,68 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); break; case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_BAD_DEST; break; case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, pm8001_printk(\ - "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_CONN_RATE; break; case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_WRONG_DEST; break; case IO_XFER_ERROR_RX_FRAME: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_RX_FRAME\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_RX_FRAME\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; break; case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_ERROR_INTERNAL_SMP_RESOURCE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ERROR_INTERNAL_SMP_RESOURCE\n")); + pm8001_dbg(pm8001_ha, IO, "IO_ERROR_INTERNAL_SMP_RESOURCE\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_QUEUE_FULL; break; case IO_PORT_IN_RESET: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_PORT_IN_RESET\n")); + pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_DS_NON_OPERATIONAL: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_NON_OPERATIONAL\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; break; case IO_DS_IN_RECOVERY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_RECOVERY\n")); + pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n")); + pm8001_dbg(pm8001_ha, IO, + "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", status)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; /* not allowed case. Therefore, return failed status */ @@ -3213,10 +3151,9 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) t->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "task 0x%p done with io_status 0x%x resp 0x%x" - "stat 0x%x but aborted by upper layer!\n", - t, status, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, + "task 0x%p done with io_status 0x%x resp 0x%xstat 0x%x but aborted by upper layer!\n", + t, status, ts->resp, ts->stat); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); @@ -3313,38 +3250,34 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) port->port_state = portstate; port->wide_port_phymap |= (1U << phy_id); phy->phy_state = PHY_STATE_LINK_UP_SPCV; - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "portid:%d; phyid:%d; linkrate:%d; " - "portstate:%x; devicetype:%x\n", - port_id, phy_id, link_rate, portstate, deviceType)); + pm8001_dbg(pm8001_ha, MSG, + "portid:%d; phyid:%d; linkrate:%d; portstate:%x; devicetype:%x\n", + port_id, phy_id, link_rate, portstate, deviceType); switch (deviceType) { case SAS_PHY_UNUSED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("device type no device.\n")); + pm8001_dbg(pm8001_ha, MSG, "device type no device.\n"); break; case SAS_END_DEVICE: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n")); + pm8001_dbg(pm8001_ha, MSG, "end device.\n"); pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id, PHY_NOTIFY_ENABLE_SPINUP); port->port_attached = 1; pm8001_get_lrate_mode(phy, link_rate); break; case SAS_EDGE_EXPANDER_DEVICE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("expander device.\n")); + pm8001_dbg(pm8001_ha, MSG, "expander device.\n"); port->port_attached = 1; pm8001_get_lrate_mode(phy, link_rate); break; case SAS_FANOUT_EXPANDER_DEVICE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("fanout expander device.\n")); + pm8001_dbg(pm8001_ha, MSG, "fanout expander device.\n"); port->port_attached = 1; pm8001_get_lrate_mode(phy, link_rate); break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("unknown device type(%x)\n", deviceType)); + pm8001_dbg(pm8001_ha, DEVIO, "unknown device type(%x)\n", + deviceType); break; } phy->phy_type |= PORT_TYPE_SAS; @@ -3363,7 +3296,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); if (pm8001_ha->flags == PM8001F_RUN_TIME) - msleep(200);/*delay a moment to wait disk to spinup*/ + mdelay(200); /* delay a moment to wait for disk to spin up */ pm8001_bytes_dmaed(pm8001_ha, phy_id); } @@ -3392,9 +3325,9 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) struct sas_ha_struct *sas_ha = pm8001_ha->sas; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; unsigned long flags; - PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( - "port id %d, phy id %d link_rate %d portstate 0x%x\n", - port_id, phy_id, link_rate, portstate)); + pm8001_dbg(pm8001_ha, DEVIO, + "port id %d, phy id %d link_rate %d portstate 0x%x\n", + port_id, phy_id, link_rate, portstate); port->port_state = portstate; phy->phy_state = PHY_STATE_LINK_UP_SPCV; @@ -3444,10 +3377,10 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) case PORT_VALID: break; case PORT_INVALID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" PortInvalid portID %d\n", port_id)); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Last phy Down and port invalid\n")); + pm8001_dbg(pm8001_ha, MSG, " PortInvalid portID %d\n", + port_id); + pm8001_dbg(pm8001_ha, MSG, + " Last phy Down and port invalid\n"); if (port_sata) { phy->phy_type = 0; port->port_attached = 0; @@ -3457,19 +3390,18 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) sas_phy_disconnected(&phy->sas_phy); break; case PORT_IN_RESET: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Port In Reset portID %d\n", port_id)); + pm8001_dbg(pm8001_ha, MSG, " Port In Reset portID %d\n", + port_id); break; case PORT_NOT_ESTABLISHED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Phy Down and PORT_NOT_ESTABLISHED\n")); + pm8001_dbg(pm8001_ha, MSG, + " Phy Down and PORT_NOT_ESTABLISHED\n"); port->port_attached = 0; break; case PORT_LOSTCOMM: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Phy Down and PORT_LOSTCOMM\n")); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Last phy Down and port invalid\n")); + pm8001_dbg(pm8001_ha, MSG, " Phy Down and PORT_LOSTCOMM\n"); + pm8001_dbg(pm8001_ha, MSG, + " Last phy Down and port invalid\n"); if (port_sata) { port->port_attached = 0; phy->phy_type = 0; @@ -3480,9 +3412,9 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) break; default: port->port_attached = 0; - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk(" Phy Down and(default) = 0x%x\n", - portstate)); + pm8001_dbg(pm8001_ha, DEVIO, + " Phy Down and(default) = 0x%x\n", + portstate); break; } @@ -3503,9 +3435,9 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) le32_to_cpu(pPayload->phyid); struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("phy start resp status:0x%x, phyid:0x%x\n", - status, phy_id)); + pm8001_dbg(pm8001_ha, INIT, + "phy start resp status:0x%x, phyid:0x%x\n", + status, phy_id); if (status == 0) { phy->phy_state = PHY_LINK_DOWN; if (pm8001_ha->flags == PM8001F_RUN_TIME && @@ -3532,18 +3464,18 @@ static int mpi_thermal_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) u32 rht_lht = le32_to_cpu(pPayload->rht_lht); if (thermal_event & 0x40) { - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Thermal Event: Local high temperature violated!\n")); - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Thermal Event: Measured local high temperature %d\n", - ((rht_lht & 0xFF00) >> 8))); + pm8001_dbg(pm8001_ha, IO, + "Thermal Event: Local high temperature violated!\n"); + pm8001_dbg(pm8001_ha, IO, + "Thermal Event: Measured local high temperature %d\n", + ((rht_lht & 0xFF00) >> 8)); } if (thermal_event & 0x10) { - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Thermal Event: Remote high temperature violated!\n")); - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Thermal Event: Measured remote high temperature %d\n", - ((rht_lht & 0xFF000000) >> 24))); + pm8001_dbg(pm8001_ha, IO, + "Thermal Event: Remote high temperature violated!\n"); + pm8001_dbg(pm8001_ha, IO, + "Thermal Event: Measured remote high temperature %d\n", + ((rht_lht & 0xFF000000) >> 24)); } return 0; } @@ -3572,42 +3504,36 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; struct pm8001_port *port = &pm8001_ha->port[port_id]; struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; - PM8001_DEV_DBG(pm8001_ha, - pm8001_printk("portid:%d phyid:%d event:0x%x status:0x%x\n", - port_id, phy_id, eventType, status)); + pm8001_dbg(pm8001_ha, DEV, + "portid:%d phyid:%d event:0x%x status:0x%x\n", + port_id, phy_id, eventType, status); switch (eventType) { case HW_EVENT_SAS_PHY_UP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_START_STATUS\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_START_STATUS\n"); hw_event_sas_phy_up(pm8001_ha, piomb); break; case HW_EVENT_SATA_PHY_UP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SATA_PHY_UP\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_PHY_UP\n"); hw_event_sata_phy_up(pm8001_ha, piomb); break; case HW_EVENT_SATA_SPINUP_HOLD: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SATA_SPINUP_HOLD\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_SPINUP_HOLD\n"); sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD); break; case HW_EVENT_PHY_DOWN: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_DOWN\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_DOWN\n"); hw_event_phy_down(pm8001_ha, piomb); if (pm8001_ha->reset_in_progress) { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Reset in progress\n")); + pm8001_dbg(pm8001_ha, MSG, "Reset in progress\n"); return 0; } phy->phy_attached = 0; phy->phy_state = PHY_LINK_DISABLE; break; case HW_EVENT_PORT_INVALID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_INVALID\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_INVALID\n"); sas_phy_disconnected(sas_phy); phy->phy_attached = 0; sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); @@ -3615,8 +3541,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) /* the broadcast change primitive received, tell the LIBSAS this event to revalidate the sas domain*/ case HW_EVENT_BROADCAST_CHANGE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_BROADCAST_CHANGE\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_CHANGE\n"); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_BROADCAST_CHANGE, port_id, phy_id, 1, 0); spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); @@ -3625,81 +3550,74 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); break; case HW_EVENT_PHY_ERROR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_ERROR\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_ERROR\n"); sas_phy_disconnected(&phy->sas_phy); phy->phy_attached = 0; sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR); break; case HW_EVENT_BROADCAST_EXP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_BROADCAST_EXP\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_EXP\n"); spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); sas_phy->sas_prim = HW_EVENT_BROADCAST_EXP; spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); break; case HW_EVENT_LINK_ERR_INVALID_DWORD: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_INVALID_DWORD\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_INVALID_DWORD\n"); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0); break; case HW_EVENT_LINK_ERR_DISPARITY_ERROR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_DISPARITY_ERROR\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_DISPARITY_ERROR\n"); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_DISPARITY_ERROR, port_id, phy_id, 0, 0); break; case HW_EVENT_LINK_ERR_CODE_VIOLATION: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_CODE_VIOLATION\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_CODE_VIOLATION\n"); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_CODE_VIOLATION, port_id, phy_id, 0, 0); break; case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n"); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH, port_id, phy_id, 0, 0); break; case HW_EVENT_MALFUNCTION: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_MALFUNCTION\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_MALFUNCTION\n"); break; case HW_EVENT_BROADCAST_SES: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_BROADCAST_SES\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_SES\n"); spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); sas_phy->sas_prim = HW_EVENT_BROADCAST_SES; spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); break; case HW_EVENT_INBOUND_CRC_ERROR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_INBOUND_CRC_ERROR\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_INBOUND_CRC_ERROR\n"); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_INBOUND_CRC_ERROR, port_id, phy_id, 0, 0); break; case HW_EVENT_HARD_RESET_RECEIVED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_HARD_RESET_RECEIVED\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_HARD_RESET_RECEIVED\n"); sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET); break; case HW_EVENT_ID_FRAME_TIMEOUT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_ID_FRAME_TIMEOUT\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_ID_FRAME_TIMEOUT\n"); sas_phy_disconnected(sas_phy); phy->phy_attached = 0; sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_LINK_ERR_PHY_RESET_FAILED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n"); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_PHY_RESET_FAILED, port_id, phy_id, 0, 0); @@ -3708,8 +3626,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_PORT_RESET_TIMER_TMO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RESET_TIMER_TMO\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_TIMER_TMO\n"); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, port_id, phy_id, 0, 0); sas_phy_disconnected(sas_phy); @@ -3723,8 +3640,8 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case HW_EVENT_PORT_RECOVERY_TIMER_TMO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RECOVERY_TIMER_TMO\n")); + pm8001_dbg(pm8001_ha, MSG, + "HW_EVENT_PORT_RECOVERY_TIMER_TMO\n"); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PORT_RECOVERY_TIMER_TMO, port_id, phy_id, 0, 0); @@ -3738,13 +3655,11 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case HW_EVENT_PORT_RECOVER: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RECOVER\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RECOVER\n"); hw_event_port_recover(pm8001_ha, piomb); break; case HW_EVENT_PORT_RESET_COMPLETE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RESET_COMPLETE\n")); + pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_COMPLETE\n"); if (pm8001_ha->phy[phy_id].reset_completion) { pm8001_ha->phy[phy_id].port_reset_status = PORT_RESET_SUCCESS; @@ -3753,12 +3668,11 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) } break; case EVENT_BROADCAST_ASYNCH_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("EVENT_BROADCAST_ASYNCH_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n"); break; default: - PM8001_DEVIO_DBG(pm8001_ha, - pm8001_printk("Unknown event type 0x%x\n", eventType)); + pm8001_dbg(pm8001_ha, DEVIO, "Unknown event type 0x%x\n", + eventType); break; } return 0; @@ -3778,9 +3692,8 @@ static int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) u32 phyid = le32_to_cpu(pPayload->phyid) & 0xFF; struct pm8001_phy *phy = &pm8001_ha->phy[phyid]; - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("phy:0x%x status:0x%x\n", - phyid, status)); + pm8001_dbg(pm8001_ha, MSG, "phy:0x%x status:0x%x\n", + phyid, status); if (status == PHY_STOP_SUCCESS || status == PHY_STOP_ERR_DEVICE_ATTACHED) phy->phy_state = PHY_LINK_DISABLE; @@ -3800,9 +3713,9 @@ static int mpi_set_controller_config_resp(struct pm8001_hba_info *pm8001_ha, u32 status = le32_to_cpu(pPayload->status); u32 err_qlfr_pgcd = le32_to_cpu(pPayload->err_qlfr_pgcd); - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "SET CONTROLLER RESP: status 0x%x qlfr_pgcd 0x%x\n", - status, err_qlfr_pgcd)); + pm8001_dbg(pm8001_ha, MSG, + "SET CONTROLLER RESP: status 0x%x qlfr_pgcd 0x%x\n", + status, err_qlfr_pgcd); return 0; } @@ -3815,8 +3728,7 @@ static int mpi_set_controller_config_resp(struct pm8001_hba_info *pm8001_ha, static int mpi_get_controller_config_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" pm80xx_addition_functionality\n")); + pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); return 0; } @@ -3829,8 +3741,7 @@ static int mpi_get_controller_config_resp(struct pm8001_hba_info *pm8001_ha, static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" pm80xx_addition_functionality\n")); + pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); return 0; } @@ -3842,8 +3753,7 @@ static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, */ static int mpi_flash_op_ext_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" pm80xx_addition_functionality\n")); + pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); return 0; } @@ -3868,15 +3778,14 @@ static int mpi_set_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, page_code = (u8)((ppc_phyid & 0xFF00) >> 8); if (status) { /* status is FAILED */ - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("PhyProfile command failed with status " - "0x%08X \n", status)); + pm8001_dbg(pm8001_ha, FAIL, + "PhyProfile command failed with status 0x%08X\n", + status); rc = -1; } else { if (page_code != SAS_PHY_ANALOG_SETTINGS_PAGE) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Invalid page code 0x%X\n", - page_code)); + pm8001_dbg(pm8001_ha, FAIL, "Invalid page code 0x%X\n", + page_code); rc = -1; } } @@ -3898,9 +3807,9 @@ static int mpi_kek_management_resp(struct pm8001_hba_info *pm8001_ha, u32 kidx_new_curr_ksop = le32_to_cpu(pPayload->kidx_new_curr_ksop); u32 err_qlfr = le32_to_cpu(pPayload->err_qlfr); - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "KEK MGMT RESP. Status 0x%x idx_ksop 0x%x err_qlfr 0x%x\n", - status, kidx_new_curr_ksop, err_qlfr)); + pm8001_dbg(pm8001_ha, MSG, + "KEK MGMT RESP. Status 0x%x idx_ksop 0x%x err_qlfr 0x%x\n", + status, kidx_new_curr_ksop, err_qlfr); return 0; } @@ -3913,8 +3822,7 @@ static int mpi_kek_management_resp(struct pm8001_hba_info *pm8001_ha, static int mpi_dek_management_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" pm80xx_addition_functionality\n")); + pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); return 0; } @@ -3927,8 +3835,7 @@ static int mpi_dek_management_resp(struct pm8001_hba_info *pm8001_ha, static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" pm80xx_addition_functionality\n")); + pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); return 0; } @@ -3945,248 +3852,206 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) switch (opc) { case OPC_OUB_ECHO: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("OPC_OUB_ECHO\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_ECHO\n"); break; case OPC_OUB_HW_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_HW_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_HW_EVENT\n"); mpi_hw_event(pm8001_ha, piomb); break; case OPC_OUB_THERM_HW_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_THERMAL_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_THERMAL_EVENT\n"); mpi_thermal_hw_event(pm8001_ha, piomb); break; case OPC_OUB_SSP_COMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_COMP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_COMP\n"); mpi_ssp_completion(pm8001_ha, piomb); break; case OPC_OUB_SMP_COMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SMP_COMP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_COMP\n"); mpi_smp_completion(pm8001_ha, piomb); break; case OPC_OUB_LOCAL_PHY_CNTRL: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_LOCAL_PHY_CNTRL\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_LOCAL_PHY_CNTRL\n"); pm8001_mpi_local_phy_ctl(pm8001_ha, piomb); break; case OPC_OUB_DEV_REGIST: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEV_REGIST\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_REGIST\n"); pm8001_mpi_reg_resp(pm8001_ha, piomb); break; case OPC_OUB_DEREG_DEV: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("unregister the device\n")); + pm8001_dbg(pm8001_ha, MSG, "unregister the device\n"); pm8001_mpi_dereg_resp(pm8001_ha, piomb); break; case OPC_OUB_GET_DEV_HANDLE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_DEV_HANDLE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEV_HANDLE\n"); break; case OPC_OUB_SATA_COMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SATA_COMP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_COMP\n"); mpi_sata_completion(pm8001_ha, piomb); break; case OPC_OUB_SATA_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SATA_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_EVENT\n"); mpi_sata_event(pm8001_ha, piomb); break; case OPC_OUB_SSP_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_EVENT\n"); mpi_ssp_event(pm8001_ha, piomb); break; case OPC_OUB_DEV_HANDLE_ARRIV: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEV_HANDLE_ARRIV\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_HANDLE_ARRIV\n"); /*This is for target*/ break; case OPC_OUB_SSP_RECV_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_RECV_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_RECV_EVENT\n"); /*This is for target*/ break; case OPC_OUB_FW_FLASH_UPDATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_FW_FLASH_UPDATE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_FW_FLASH_UPDATE\n"); pm8001_mpi_fw_flash_update_resp(pm8001_ha, piomb); break; case OPC_OUB_GPIO_RESPONSE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GPIO_RESPONSE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_RESPONSE\n"); break; case OPC_OUB_GPIO_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GPIO_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_EVENT\n"); break; case OPC_OUB_GENERAL_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GENERAL_EVENT\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GENERAL_EVENT\n"); pm8001_mpi_general_event(pm8001_ha, piomb); break; case OPC_OUB_SSP_ABORT_RSP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_ABORT_RSP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_ABORT_RSP\n"); pm8001_mpi_task_abort_resp(pm8001_ha, piomb); break; case OPC_OUB_SATA_ABORT_RSP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SATA_ABORT_RSP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_ABORT_RSP\n"); pm8001_mpi_task_abort_resp(pm8001_ha, piomb); break; case OPC_OUB_SAS_DIAG_MODE_START_END: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_DIAG_MODE_START_END\n")); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_SAS_DIAG_MODE_START_END\n"); break; case OPC_OUB_SAS_DIAG_EXECUTE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_DIAG_EXECUTE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_DIAG_EXECUTE\n"); break; case OPC_OUB_GET_TIME_STAMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_TIME_STAMP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_TIME_STAMP\n"); break; case OPC_OUB_SAS_HW_EVENT_ACK: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_HW_EVENT_ACK\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_HW_EVENT_ACK\n"); break; case OPC_OUB_PORT_CONTROL: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_PORT_CONTROL\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_PORT_CONTROL\n"); break; case OPC_OUB_SMP_ABORT_RSP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SMP_ABORT_RSP\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_ABORT_RSP\n"); pm8001_mpi_task_abort_resp(pm8001_ha, piomb); break; case OPC_OUB_GET_NVMD_DATA: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_NVMD_DATA\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_NVMD_DATA\n"); pm8001_mpi_get_nvmd_resp(pm8001_ha, piomb); break; case OPC_OUB_SET_NVMD_DATA: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SET_NVMD_DATA\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_NVMD_DATA\n"); pm8001_mpi_set_nvmd_resp(pm8001_ha, piomb); break; case OPC_OUB_DEVICE_HANDLE_REMOVAL: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEVICE_HANDLE_REMOVAL\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEVICE_HANDLE_REMOVAL\n"); break; case OPC_OUB_SET_DEVICE_STATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SET_DEVICE_STATE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEVICE_STATE\n"); pm8001_mpi_set_dev_state_resp(pm8001_ha, piomb); break; case OPC_OUB_GET_DEVICE_STATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_DEVICE_STATE\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEVICE_STATE\n"); break; case OPC_OUB_SET_DEV_INFO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SET_DEV_INFO\n")); + pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEV_INFO\n"); break; /* spcv specifc commands */ case OPC_OUB_PHY_START_RESP: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_PHY_START_RESP opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_PHY_START_RESP opcode:%x\n", opc); mpi_phy_start_resp(pm8001_ha, piomb); break; case OPC_OUB_PHY_STOP_RESP: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_PHY_STOP_RESP opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_PHY_STOP_RESP opcode:%x\n", opc); mpi_phy_stop_resp(pm8001_ha, piomb); break; case OPC_OUB_SET_CONTROLLER_CONFIG: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_SET_CONTROLLER_CONFIG opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_SET_CONTROLLER_CONFIG opcode:%x\n", opc); mpi_set_controller_config_resp(pm8001_ha, piomb); break; case OPC_OUB_GET_CONTROLLER_CONFIG: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_GET_CONTROLLER_CONFIG opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_GET_CONTROLLER_CONFIG opcode:%x\n", opc); mpi_get_controller_config_resp(pm8001_ha, piomb); break; case OPC_OUB_GET_PHY_PROFILE: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_GET_PHY_PROFILE opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_GET_PHY_PROFILE opcode:%x\n", opc); mpi_get_phy_profile_resp(pm8001_ha, piomb); break; case OPC_OUB_FLASH_OP_EXT: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_FLASH_OP_EXT opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_FLASH_OP_EXT opcode:%x\n", opc); mpi_flash_op_ext_resp(pm8001_ha, piomb); break; case OPC_OUB_SET_PHY_PROFILE: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_SET_PHY_PROFILE opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_SET_PHY_PROFILE opcode:%x\n", opc); mpi_set_phy_profile_resp(pm8001_ha, piomb); break; case OPC_OUB_KEK_MANAGEMENT_RESP: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_KEK_MANAGEMENT_RESP opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_KEK_MANAGEMENT_RESP opcode:%x\n", opc); mpi_kek_management_resp(pm8001_ha, piomb); break; case OPC_OUB_DEK_MANAGEMENT_RESP: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_DEK_MANAGEMENT_RESP opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_DEK_MANAGEMENT_RESP opcode:%x\n", opc); mpi_dek_management_resp(pm8001_ha, piomb); break; case OPC_OUB_SSP_COALESCED_COMP_RESP: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( - "OPC_OUB_SSP_COALESCED_COMP_RESP opcode:%x\n", opc)); + pm8001_dbg(pm8001_ha, MSG, + "OPC_OUB_SSP_COALESCED_COMP_RESP opcode:%x\n", opc); ssp_coalesced_comp_resp(pm8001_ha, piomb); break; default: - PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( - "Unknown outbound Queue IOMB OPC = 0x%x\n", opc)); + pm8001_dbg(pm8001_ha, DEVIO, + "Unknown outbound Queue IOMB OPC = 0x%x\n", opc); break; } } static void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_SCRATCH_PAD_0: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_SCRATCH_PAD_1:0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_SCRATCH_PAD_2: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_SCRATCH_PAD_3: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_HOST_SCRATCH_PAD_0: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_HOST_SCRATCH_PAD_1: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_HOST_SCRATCH_PAD_2: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_HOST_SCRATCH_PAD_3: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_HOST_SCRATCH_PAD_4: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_HOST_SCRATCH_PAD_5: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_7))); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_0: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_1:0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_2: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_3: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_0: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_1: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_2: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_3: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_4: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_5: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6)); + pm8001_dbg(pm8001_ha, FAIL, "MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_7)); } static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) @@ -4203,8 +4068,9 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) if ((regval & SCRATCH_PAD_MIPSALL_READY) != SCRATCH_PAD_MIPSALL_READY) { pm8001_ha->controller_fatal_error = true; - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "Firmware Fatal error! Regval:0x%x\n", regval)); + pm8001_dbg(pm8001_ha, FAIL, + "Firmware Fatal error! Regval:0x%x\n", + regval); print_scratchpad_registers(pm8001_ha); return ret; } @@ -4281,7 +4147,6 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, char *preq_dma_addr = NULL; __le64 tmp_addr; u32 i, length; - unsigned long flags; memset(&smp_cmd, 0, sizeof(smp_cmd)); /* @@ -4311,8 +4176,7 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, smp_cmd.tag = cpu_to_le32(ccb->ccb_tag); length = sg_req->length; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("SMP Frame Length %d\n", sg_req->length)); + pm8001_dbg(pm8001_ha, IO, "SMP Frame Length %d\n", sg_req->length); if (!(length - 8)) pm8001_ha->smp_exp_mode = SMP_DIRECT; else @@ -4324,8 +4188,7 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, /* INDIRECT MODE command settings. Use DMA */ if (pm8001_ha->smp_exp_mode == SMP_INDIRECT) { - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("SMP REQUEST INDIRECT MODE\n")); + pm8001_dbg(pm8001_ha, IO, "SMP REQUEST INDIRECT MODE\n"); /* for SPCv indirect mode. Place the top 4 bytes of * SMP Request header here. */ for (i = 0; i < 4; i++) @@ -4357,30 +4220,27 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, ((u32)sg_dma_len(&task->smp_task.smp_resp)-4); } if (pm8001_ha->smp_exp_mode == SMP_DIRECT) { - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("SMP REQUEST DIRECT MODE\n")); + pm8001_dbg(pm8001_ha, IO, "SMP REQUEST DIRECT MODE\n"); for (i = 0; i < length; i++) if (i < 16) { smp_cmd.smp_req16[i] = *(preq_dma_addr+i); - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Byte[%d]:%x (DMA data:%x)\n", - i, smp_cmd.smp_req16[i], - *(preq_dma_addr))); + pm8001_dbg(pm8001_ha, IO, + "Byte[%d]:%x (DMA data:%x)\n", + i, smp_cmd.smp_req16[i], + *(preq_dma_addr)); } else { smp_cmd.smp_req[i] = *(preq_dma_addr+i); - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Byte[%d]:%x (DMA data:%x)\n", - i, smp_cmd.smp_req[i], - *(preq_dma_addr))); + pm8001_dbg(pm8001_ha, IO, + "Byte[%d]:%x (DMA data:%x)\n", + i, smp_cmd.smp_req[i], + *(preq_dma_addr)); } } build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, &smp_cmd, pm8001_ha->smp_exp_mode, length); - spin_lock_irqsave(&circularQ->iq_lock, flags); rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &smp_cmd, sizeof(smp_cmd), 0); - spin_unlock_irqrestore(&circularQ->iq_lock, flags); if (rc) goto err_out_2; return 0; @@ -4444,7 +4304,6 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, u64 phys_addr, start_addr, end_addr; u32 end_addr_high, end_addr_low; struct inbound_queue_table *circularQ; - unsigned long flags; u32 q_index, cpu_id; u32 opc = OPC_INB_SSPINIIOSTART; memset(&ssp_cmd, 0, sizeof(ssp_cmd)); @@ -4471,9 +4330,9 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, /* Check if encryption is set */ if (pm8001_ha->chip->encrypt && !(pm8001_ha->encrypt_info.status) && check_enc_sas_cmd(task)) { - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Encryption enabled.Sending Encrypt SAS command 0x%x\n", - task->ssp_task.cmd->cmnd[0])); + pm8001_dbg(pm8001_ha, IO, + "Encryption enabled.Sending Encrypt SAS command 0x%x\n", + task->ssp_task.cmd->cmnd[0]); opc = OPC_INB_SSP_INI_DIF_ENC_IO; /* enable encryption. 0 for SAS 1.1 and SAS 2.0 compatible TLR*/ ssp_cmd.dad_dir_m_tlr = cpu_to_le32 @@ -4503,13 +4362,10 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); if (end_addr_high != ssp_cmd.enc_addr_high) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("The sg list address " - "start_addr=0x%016llx data_len=0x%x " - "end_addr_high=0x%08x end_addr_low=" - "0x%08x has crossed 4G boundary\n", - start_addr, ssp_cmd.enc_len, - end_addr_high, end_addr_low)); + pm8001_dbg(pm8001_ha, FAIL, + "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", + start_addr, ssp_cmd.enc_len, + end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; @@ -4533,9 +4389,9 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, (task->ssp_task.cmd->cmnd[4] << 8) | (task->ssp_task.cmd->cmnd[5])); } else { - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Sending Normal SAS command 0x%x inb q %x\n", - task->ssp_task.cmd->cmnd[0], q_index)); + pm8001_dbg(pm8001_ha, IO, + "Sending Normal SAS command 0x%x inb q %x\n", + task->ssp_task.cmd->cmnd[0], q_index); /* fill in PRD (scatter/gather) table, if any */ if (task->num_scatter > 1) { pm8001_chip_make_sg(task->scatter, ccb->n_elem, @@ -4559,13 +4415,10 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); if (end_addr_high != ssp_cmd.addr_high) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("The sg list address " - "start_addr=0x%016llx data_len=0x%x " - "end_addr_high=0x%08x end_addr_low=" - "0x%08x has crossed 4G boundary\n", - start_addr, ssp_cmd.len, - end_addr_high, end_addr_low)); + pm8001_dbg(pm8001_ha, FAIL, + "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", + start_addr, ssp_cmd.len, + end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; @@ -4582,10 +4435,8 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.esgl = 0; } } - spin_lock_irqsave(&circularQ->iq_lock, flags); ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &ssp_cmd, sizeof(ssp_cmd), q_index); - spin_unlock_irqrestore(&circularQ->iq_lock, flags); return ret; } @@ -4614,19 +4465,19 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, if (task->data_dir == DMA_NONE) { ATAP = 0x04; /* no data*/ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("no data\n")); + pm8001_dbg(pm8001_ha, IO, "no data\n"); } else if (likely(!task->ata_task.device_control_reg_update)) { if (task->ata_task.dma_xfer) { ATAP = 0x06; /* DMA */ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("DMA\n")); + pm8001_dbg(pm8001_ha, IO, "DMA\n"); } else { ATAP = 0x05; /* PIO*/ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("PIO\n")); + pm8001_dbg(pm8001_ha, IO, "PIO\n"); } if (task->ata_task.use_ncq && dev->sata_dev.class != ATA_DEV_ATAPI) { ATAP = 0x07; /* FPDMA */ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("FPDMA\n")); + pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); } } if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { @@ -4646,9 +4497,9 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, /* Check if encryption is set */ if (pm8001_ha->chip->encrypt && !(pm8001_ha->encrypt_info.status) && check_enc_sat_cmd(task)) { - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Encryption enabled.Sending Encrypt SATA cmd 0x%x\n", - sata_cmd.sata_fis.command)); + pm8001_dbg(pm8001_ha, IO, + "Encryption enabled.Sending Encrypt SATA cmd 0x%x\n", + sata_cmd.sata_fis.command); opc = OPC_INB_SATA_DIF_ENC_IO; /* set encryption bit */ @@ -4676,13 +4527,10 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); if (end_addr_high != sata_cmd.enc_addr_high) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("The sg list address " - "start_addr=0x%016llx data_len=0x%x " - "end_addr_high=0x%08x end_addr_low" - "=0x%08x has crossed 4G boundary\n", - start_addr, sata_cmd.enc_len, - end_addr_high, end_addr_low)); + pm8001_dbg(pm8001_ha, FAIL, + "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", + start_addr, sata_cmd.enc_len, + end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; @@ -4711,9 +4559,9 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, cpu_to_le32((sata_cmd.sata_fis.lbah_exp << 8) | (sata_cmd.sata_fis.lbam_exp)); } else { - PM8001_IO_DBG(pm8001_ha, pm8001_printk( - "Sending Normal SATA command 0x%x inb %x\n", - sata_cmd.sata_fis.command, q_index)); + pm8001_dbg(pm8001_ha, IO, + "Sending Normal SATA command 0x%x inb %x\n", + sata_cmd.sata_fis.command, q_index); /* dad (bit 0-1) is 0 */ sata_cmd.ncqtag_atap_dir_m_dad = cpu_to_le32(((ncg_tag & 0xff)<<16) | @@ -4739,13 +4587,10 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); if (end_addr_high != sata_cmd.addr_high) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("The sg list address " - "start_addr=0x%016llx data_len=0x%x" - "end_addr_high=0x%08x end_addr_low=" - "0x%08x has crossed 4G boundary\n", - start_addr, sata_cmd.len, - end_addr_high, end_addr_low)); + pm8001_dbg(pm8001_ha, FAIL, + "The sg list address start_addr=0x%016llx data_len=0x%xend_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", + start_addr, sata_cmd.len, + end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; @@ -4804,10 +4649,10 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&task->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task 0x%p resp 0x%x " - " stat 0x%x but aborted by upper layer " - "\n", task, ts->resp, ts->stat)); + pm8001_dbg(pm8001_ha, FAIL, + "task 0x%p resp 0x%x stat 0x%x but aborted by upper layer\n", + task, ts->resp, + ts->stat); pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); return 0; } else { @@ -4815,14 +4660,13 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, flags); pm8001_ccb_task_free_done(pm8001_ha, task, ccb, tag); + atomic_dec(&pm8001_ha_dev->running_req); return 0; } } } - spin_lock_irqsave(&circularQ->iq_lock, flags); ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, sizeof(sata_cmd), q_index); - spin_unlock_irqrestore(&circularQ->iq_lock, flags); return ret; } @@ -4843,8 +4687,7 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) memset(&payload, 0, sizeof(payload)); payload.tag = cpu_to_le32(tag); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PHY START REQ for phy_id %d\n", phy_id)); + pm8001_dbg(pm8001_ha, INIT, "PHY START REQ for phy_id %d\n", phy_id); payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | LINKMODE_AUTO | pm8001_ha->link_rate | phy_id); @@ -5008,9 +4851,9 @@ static irqreturn_t pm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec) { pm80xx_chip_interrupt_disable(pm8001_ha, vec); - PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( - "irq vec %d, ODMR:0x%x\n", - vec, pm8001_cr32(pm8001_ha, 0, 0x30))); + pm8001_dbg(pm8001_ha, DEVIO, + "irq vec %d, ODMR:0x%x\n", + vec, pm8001_cr32(pm8001_ha, 0, 0x30)); process_oq(pm8001_ha, vec); pm80xx_chip_interrupt_enable(pm8001_ha, vec); return IRQ_HANDLED; @@ -5029,13 +4872,13 @@ static void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha, memset(&payload, 0, sizeof(payload)); rc = pm8001_tag_alloc(pm8001_ha, &tag); if (rc) - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("Invalid tag\n")); + pm8001_dbg(pm8001_ha, FAIL, "Invalid tag\n"); circularQ = &pm8001_ha->inbnd_q_tbl[0]; payload.tag = cpu_to_le32(tag); payload.ppc_phyid = (((operation & 0xF) << 8) | (phyid & 0xFF)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk(" phy profile command for phy %x ,length is %d\n", - payload.ppc_phyid, length)); + pm8001_dbg(pm8001_ha, INIT, + " phy profile command for phy %x ,length is %d\n", + payload.ppc_phyid, length); for (i = length; i < (length + PHY_DWORD_LENGTH - 1); i++) { payload.reserved[j] = cpu_to_le32(*((u32 *)buf + i)); j++; @@ -5056,7 +4899,7 @@ void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, SAS_PHY_ANALOG_SETTINGS_PAGE, i, length, (u32 *)buf); length = length + PHY_DWORD_LENGTH; } - PM8001_INIT_DBG(pm8001_ha, pm8001_printk("phy settings completed\n")); + pm8001_dbg(pm8001_ha, INIT, "phy settings completed\n"); } void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, @@ -5071,7 +4914,7 @@ void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, rc = pm8001_tag_alloc(pm8001_ha, &tag); if (rc) - PM8001_INIT_DBG(pm8001_ha, pm8001_printk("Invalid tag")); + pm8001_dbg(pm8001_ha, INIT, "Invalid tag\n"); circularQ = &pm8001_ha->inbnd_q_tbl[0]; opc = OPC_INB_SET_PHY_PROFILE; @@ -5088,8 +4931,7 @@ void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, if (rc) pm8001_tag_free(pm8001_ha, tag); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PHY %d settings applied", phy)); + pm8001_dbg(pm8001_ha, INIT, "PHY %d settings applied\n", phy); } const struct pm8001_dispatch pm8001_80xx_dispatch = { .name = "pmc80xx", diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index 701951a0f715..ec48bc276de6 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -1639,3 +1639,9 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t; #define MEMBASE_II_SHIFT_REGISTER 0x1010 #endif + +/** + * As we know sleep (1~20) ms may result in sleep longer than ~20 ms, hence we + * choose 20 ms interval. + */ +#define FW_READY_INTERVAL 20 diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index cbe5fab793eb..834556ea21d2 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -5234,54 +5234,37 @@ static void pmcraid_remove(struct pci_dev *pdev) return; } -#ifdef CONFIG_PM /** * pmcraid_suspend - driver suspend entry point for power management - * @pdev: PCI device structure - * @state: PCI power state to suspend routine + * @dev: Device structure * * Return Value - 0 always */ -static int pmcraid_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused pmcraid_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); pmcraid_shutdown(pdev); pmcraid_disable_interrupts(pinstance, ~0); pmcraid_kill_tasklets(pinstance); - pci_set_drvdata(pinstance->pdev, pinstance); pmcraid_unregister_interrupt_handler(pinstance); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } /** * pmcraid_resume - driver resume entry point PCI power management - * @pdev: PCI device structure + * @dev: Device structure * * Return Value - 0 in case of success. Error code in case of any failure */ -static int pmcraid_resume(struct pci_dev *pdev) +static int __maybe_unused pmcraid_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); struct Scsi_Host *host = pinstance->host; - int rc; - - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - rc = pci_enable_device(pdev); - - if (rc) { - dev_err(&pdev->dev, "resume: Enable device failed\n"); - return rc; - } - - pci_set_master(pdev); + int rc = 0; if (sizeof(dma_addr_t) == 4 || dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) @@ -5334,18 +5317,10 @@ release_host: scsi_host_put(host); disable_device: - pci_disable_device(pdev); return rc; } -#else - -#define pmcraid_suspend NULL -#define pmcraid_resume NULL - -#endif /* CONFIG_PM */ - /** * pmcraid_complete_ioa_reset - Called by either timer or tasklet during * completion of the ioa reset @@ -5833,6 +5808,8 @@ out_disable_device: return -ENODEV; } +static SIMPLE_DEV_PM_OPS(pmcraid_pm_ops, pmcraid_suspend, pmcraid_resume); + /* * PCI driver structure of pmcraid driver */ @@ -5841,8 +5818,7 @@ static struct pci_driver pmcraid_driver = { .id_table = pmcraid_pci_table, .probe = pmcraid_probe, .remove = pmcraid_remove, - .suspend = pmcraid_suspend, - .resume = pmcraid_resume, + .driver.pm = &pmcraid_pm_ops, .shutdown = pmcraid_shutdown }; diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h index 0e2cbb164eeb..88a592d09433 100644 --- a/drivers/scsi/qedf/qedf.h +++ b/drivers/scsi/qedf/qedf.h @@ -11,7 +11,6 @@ #include <scsi/fc/fc_fip.h> #include <scsi/fc/fc_fc2.h> #include <scsi/scsi_tcq.h> -#include <scsi/fc_encode.h> #include <linux/version.h> diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 61fab01d2d52..f5fc7f518f8a 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -2766,7 +2766,7 @@ retry_probe: QEDI_ERR(&qedi->dbg_ctx, "Unable to start offload thread!\n"); rc = -ENODEV; - goto free_cid_que; + goto free_tmf_thread; } INIT_DELAYED_WORK(&qedi->recovery_work, qedi_recovery_handler); @@ -2790,6 +2790,8 @@ retry_probe: return 0; +free_tmf_thread: + destroy_workqueue(qedi->tmf_thread); free_cid_que: qedi_release_cid_que(qedi); free_uio: diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 4f0486fe30dd..30c7e5e63851 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2493,6 +2493,8 @@ typedef struct fc_port { int generation; struct se_session *se_sess; + struct list_head sess_cmd_list; + spinlock_t sess_cmd_lock; struct kref sess_kref; struct qla_tgt *tgt; unsigned long expires; @@ -3294,8 +3296,10 @@ struct isp_operations { void (*fw_dump)(struct scsi_qla_host *vha); void (*mpi_fw_dump)(struct scsi_qla_host *, int); + /* Context: task, might sleep */ int (*beacon_on) (struct scsi_qla_host *); int (*beacon_off) (struct scsi_qla_host *); + void (*beacon_blink) (struct scsi_qla_host *); void *(*read_optrom)(struct scsi_qla_host *, void *, @@ -3306,7 +3310,10 @@ struct isp_operations { int (*get_flash_version) (struct scsi_qla_host *, void *); int (*start_scsi) (srb_t *); int (*start_scsi_mq) (srb_t *); + + /* Context: task, might sleep */ int (*abort_isp) (struct scsi_qla_host *); + int (*iospace_config)(struct qla_hw_data *); int (*initialize_adapter)(struct scsi_qla_host *); }; @@ -4968,8 +4975,7 @@ struct secure_flash_update_block_pk { } while (0) #define QLA_QPAIR_MARK_NOT_BUSY(__qpair) \ - atomic_dec(&__qpair->ref_count); \ - + atomic_dec(&__qpair->ref_count) #define QLA_ENA_CONF(_ha) {\ int i;\ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index e28c4b7ec55f..391ac75e3de3 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3558,10 +3558,10 @@ login_logout: if (fcport->flags & FCF_FCP2_DEVICE) fcport->logout_on_delete = 0; - ql_dbg(ql_dbg_disc, vha, 0x20f0, - "%s %d %8phC post del sess\n", - __func__, __LINE__, - fcport->port_name); + ql_log(ql_log_warn, vha, 0x20f0, + "%s %d %8phC post del sess\n", + __func__, __LINE__, + fcport->port_name); qlt_schedule_sess_for_deletion(fcport); continue; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 898c70b8ebbf..dcc0f0d823db 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1268,9 +1268,10 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport) lio->u.logio.flags |= SRB_LOGIN_NVME_PRLI; ql_dbg(ql_dbg_disc, vha, 0x211b, - "Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d %s.\n", + "Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d fc4type %x priority %x %s.\n", fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24, - fcport->login_retry, NVME_TARGET(vha->hw, fcport) ? "nvme" : "fc"); + fcport->login_retry, fcport->fc4_type, vha->hw->fc4_type_priority, + NVME_TARGET(vha->hw, fcport) ? "nvme" : "fcp"); rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { @@ -1932,26 +1933,58 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea) break; } - /* - * Retry PRLI with other FC-4 type if failure occurred on dual - * FCP/NVMe port - */ - if (NVME_FCP_TARGET(ea->fcport)) { - ql_dbg(ql_dbg_disc, vha, 0x2118, - "%s %d %8phC post %s prli\n", - __func__, __LINE__, ea->fcport->port_name, - (ea->fcport->fc4_type & FS_FC4TYPE_NVME) ? - "NVMe" : "FCP"); - if (vha->hw->fc4_type_priority == FC4_PRIORITY_NVME) + ql_dbg(ql_dbg_disc, vha, 0x2118, + "%s %d %8phC priority %s, fc4type %x\n", + __func__, __LINE__, ea->fcport->port_name, + vha->hw->fc4_type_priority == FC4_PRIORITY_FCP ? + "FCP" : "NVMe", ea->fcport->fc4_type); + + if (N2N_TOPO(vha->hw)) { + if (vha->hw->fc4_type_priority == FC4_PRIORITY_NVME) { ea->fcport->fc4_type &= ~FS_FC4TYPE_NVME; - else + ea->fcport->fc4_type |= FS_FC4TYPE_FCP; + } else { ea->fcport->fc4_type &= ~FS_FC4TYPE_FCP; - } + ea->fcport->fc4_type |= FS_FC4TYPE_NVME; + } - ea->fcport->flags &= ~FCF_ASYNC_SENT; - ea->fcport->keep_nport_handle = 0; - ea->fcport->logout_on_delete = 1; - qlt_schedule_sess_for_deletion(ea->fcport); + if (ea->fcport->n2n_link_reset_cnt < 3) { + ea->fcport->n2n_link_reset_cnt++; + vha->relogin_jif = jiffies + 2 * HZ; + /* + * PRLI failed. Reset link to kick start + * state machine + */ + set_bit(N2N_LINK_RESET, &vha->dpc_flags); + } else { + ql_log(ql_log_warn, vha, 0x2119, + "%s %d %8phC Unable to reconnect\n", + __func__, __LINE__, + ea->fcport->port_name); + } + } else { + /* + * switch connect. login failed. Take connection down + * and allow relogin to retrigger + */ + if (NVME_FCP_TARGET(ea->fcport)) { + ql_dbg(ql_dbg_disc, vha, 0x2118, + "%s %d %8phC post %s prli\n", + __func__, __LINE__, + ea->fcport->port_name, + (ea->fcport->fc4_type & FS_FC4TYPE_NVME) + ? "NVMe" : "FCP"); + if (vha->hw->fc4_type_priority == FC4_PRIORITY_NVME) + ea->fcport->fc4_type &= ~FS_FC4TYPE_NVME; + else + ea->fcport->fc4_type &= ~FS_FC4TYPE_FCP; + } + + ea->fcport->flags &= ~FCF_ASYNC_SENT; + ea->fcport->keep_nport_handle = 0; + ea->fcport->logout_on_delete = 1; + qlt_schedule_sess_for_deletion(ea->fcport); + } break; } } @@ -4974,6 +5007,9 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) INIT_LIST_HEAD(&fcport->gnl_entry); INIT_LIST_HEAD(&fcport->list); + INIT_LIST_HEAD(&fcport->sess_cmd_list); + spin_lock_init(&fcport->sess_cmd_lock); + return fcport; } @@ -5946,6 +5982,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) break; } + if (fcport->login_retry == 0) + fcport->login_retry = + vha->hw->login_retry_count; /* * If device was not a fabric device before. */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index a24b82de4aab..f9142dbec112 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2226,11 +2226,13 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) srb_t *sp; struct srb_iocb *iocb; struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; + u16 comp_status; sp = qla2x00_get_sp_from_handle(vha, func, req, tsk); if (!sp) return; + comp_status = le16_to_cpu(sts->comp_status); iocb = &sp->u.iocb_cmd; type = sp->name; fcport = sp->fcport; @@ -2244,7 +2246,7 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) } else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) { ql_log(ql_log_warn, fcport->vha, 0x5039, "Async-%s error - hdl=%x completion status(%x).\n", - type, sp->handle, sts->comp_status); + type, sp->handle, comp_status); iocb->u.tmf.data = QLA_FUNCTION_FAILED; } else if ((le16_to_cpu(sts->scsi_status) & SS_RESPONSE_INFO_LEN_VALID)) { @@ -2260,6 +2262,30 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) } } + switch (comp_status) { + case CS_PORT_LOGGED_OUT: + case CS_PORT_CONFIG_CHG: + case CS_PORT_BUSY: + case CS_INCOMPLETE: + case CS_PORT_UNAVAILABLE: + case CS_TIMEOUT: + case CS_RESET: + if (atomic_read(&fcport->state) == FCS_ONLINE) { + ql_dbg(ql_dbg_disc, fcport->vha, 0x3021, + "-Port to be marked lost on fcport=%02x%02x%02x, current port state= %s comp_status %x.\n", + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, + port_state_str[FCS_ONLINE], + comp_status); + + qlt_schedule_sess_for_deletion(fcport); + } + break; + + default: + break; + } + if (iocb->u.tmf.data != QLA_SUCCESS) ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, sp->vha, 0x5055, sts, sizeof(*sts)); @@ -3952,10 +3978,12 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) if (USER_CTRL_IRQ(ha) || !ha->mqiobase) { /* user wants to control IRQ setting for target mode */ ret = pci_alloc_irq_vectors(ha->pdev, min_vecs, - ha->msix_count, PCI_IRQ_MSIX); + min((u16)ha->msix_count, (u16)num_online_cpus()), + PCI_IRQ_MSIX); } else ret = pci_alloc_irq_vectors_affinity(ha->pdev, min_vecs, - ha->msix_count, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, + min((u16)ha->msix_count, (u16)num_online_cpus()), + PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, &desc); if (ret < 0) { diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 07afd0d8a8f3..d7d4ab65009c 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1129,7 +1129,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) if (ha->flags.scm_supported_a && (ha->fw_attributes_ext[0] & FW_ATTR_EXT0_SCM_SUPPORTED)) { ha->flags.scm_supported_f = 1; - ha->sf_init_cb->flags |= BIT_13; + ha->sf_init_cb->flags |= cpu_to_le16(BIT_13); } ql_log(ql_log_info, vha, 0x11a3, "SCM in FW: %s\n", (ha->flags.scm_supported_f) ? "Supported" : @@ -1137,9 +1137,9 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) if (vha->flags.nvme2_enabled) { /* set BIT_15 of special feature control block for SLER */ - ha->sf_init_cb->flags |= BIT_15; + ha->sf_init_cb->flags |= cpu_to_le16(BIT_15); /* set BIT_14 of special feature control block for PI CTRL*/ - ha->sf_init_cb->flags |= BIT_14; + ha->sf_init_cb->flags |= cpu_to_le16(BIT_14); } } @@ -3998,9 +3998,6 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, fcport->scan_state = QLA_FCPORT_FOUND; fcport->n2n_flag = 1; fcport->keep_nport_handle = 1; - fcport->fc4_type = FS_FC4TYPE_FCP; - if (vha->flags.nvme_enabled) - fcport->fc4_type |= FS_FC4TYPE_NVME; if (wwn_to_u64(vha->port_name) > wwn_to_u64(fcport->port_name)) { @@ -4030,7 +4027,6 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags); return; - break; case TOPO_FL: ha->current_topology = ISP_CFG_FL; break; diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index b7a1dc24db38..eab559b3b257 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -227,7 +227,7 @@ static void qla_nvme_abort_work(struct work_struct *work) "%s called for sp=%p, hndl=%x on fcport=%p deleted=%d\n", __func__, sp, sp->handle, fcport, fcport->deleted); - if (!ha->flags.fw_started && fcport->deleted) + if (!ha->flags.fw_started || fcport->deleted) goto out; if (ha->flags.host_shutting_down) { @@ -554,19 +554,15 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, fcport = qla_rport->fcport; - if (!qpair || !fcport) - return -ENODEV; - - if (!qpair->fw_started || fcport->deleted) + if (unlikely(!qpair || !fcport || fcport->deleted)) return -EBUSY; - vha = fcport->vha; - if (!(fcport->nvme_flag & NVME_FLAG_REGISTERED)) return -ENODEV; - if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - (qpair && !qpair->fw_started) || fcport->deleted) + vha = fcport->vha; + + if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) return -EBUSY; /* diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index b3ba0de5d4fb..0677295957bc 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -489,29 +489,26 @@ qla82xx_rd_32(struct qla_hw_data *ha, ulong off_in) return data; } -#define IDC_LOCK_TIMEOUT 100000000 +/* + * Context: task, might sleep + */ int qla82xx_idc_lock(struct qla_hw_data *ha) { - int i; - int done = 0, timeout = 0; + const int delay_ms = 100, timeout_ms = 2000; + int done, total = 0; - while (!done) { + might_sleep(); + + while (true) { /* acquire semaphore5 from PCI HW block */ done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK)); if (done == 1) break; - if (timeout >= IDC_LOCK_TIMEOUT) + if (WARN_ON_ONCE(total >= timeout_ms)) return -1; - timeout++; - - /* Yield CPU */ - if (!in_interrupt()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); - } + total += delay_ms; + msleep(delay_ms); } return 0; @@ -965,7 +962,7 @@ qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val) static int qla82xx_flash_wait_write_finish(struct qla_hw_data *ha) { - uint32_t val; + uint32_t val = 0; int i, ret; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index 01ccd4526707..68a16c95dcb7 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c @@ -139,7 +139,7 @@ qla8044_poll_wait_for_ready(struct scsi_qla_host *vha, uint32_t addr1, uint32_t mask) { unsigned long timeout; - uint32_t temp; + uint32_t temp = 0; /* jiffies after 100ms */ timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS); @@ -2594,7 +2594,7 @@ qla8044_minidump_process_rdmux(struct scsi_qla_host *vha, struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) { - uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value; + uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value = 0; struct qla8044_minidump_entry_mux *mux_hdr; uint32_t *data_ptr = *d_ptr; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f9c8ae9d669e..f80abe28f35a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -884,8 +884,8 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) goto qc24_fail_command; } - if (!fcport) { - cmd->result = DID_NO_CONNECT << 16; + if (!fcport || fcport->deleted) { + cmd->result = DID_IMM_RETRY << 16; goto qc24_fail_command; } @@ -966,8 +966,8 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, goto qc24_fail_command; } - if (!fcport) { - cmd->result = DID_NO_CONNECT << 16; + if (!fcport || fcport->deleted) { + cmd->result = DID_IMM_RETRY << 16; goto qc24_fail_command; } @@ -3265,7 +3265,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n", req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out); - ha->wq = alloc_workqueue("qla2xxx_wq", 0, 0); + ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 0); if (unlikely(!ha->wq)) { ret = -ENOMEM; goto probe_failed; @@ -5619,25 +5619,10 @@ qla83xx_service_idc_aen(struct work_struct *work) } } -static void -qla83xx_wait_logic(void) -{ - int i; - - /* Yield CPU */ - if (!in_interrupt()) { - /* - * Wait about 200ms before retrying again. - * This controls the number of retries for single - * lock operation. - */ - msleep(100); - schedule(); - } else { - for (i = 0; i < 20; i++) - cpu_relax(); /* This a nop instr on i386 */ - } -} +/* + * Control the frequency of IDC lock retries + */ +#define QLA83XX_WAIT_LOGIC_MS 100 static int qla83xx_force_lock_recovery(scsi_qla_host_t *base_vha) @@ -5727,7 +5712,7 @@ retry_lockid: goto exit; if (o_drv_lockid == n_drv_lockid) { - qla83xx_wait_logic(); + msleep(QLA83XX_WAIT_LOGIC_MS); goto retry_lockid; } else return QLA_SUCCESS; @@ -5736,6 +5721,9 @@ exit: return rval; } +/* + * Context: task, can sleep + */ void qla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id) { @@ -5743,6 +5731,8 @@ qla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id) uint32_t lock_owner; struct qla_hw_data *ha = base_vha->hw; + might_sleep(); + /* IDC-lock implementation using driver-lock/lock-id remote registers */ retry_lock: if (qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCK, &data) @@ -5761,7 +5751,7 @@ retry_lock: /* Retry/Perform IDC-Lock recovery */ if (qla83xx_idc_lock_recovery(base_vha) == QLA_SUCCESS) { - qla83xx_wait_logic(); + msleep(QLA83XX_WAIT_LOGIC_MS); goto retry_lock; } else ql_log(ql_log_warn, base_vha, 0xb075, @@ -6259,6 +6249,9 @@ void qla24xx_process_purex_list(struct purex_list *list) } } +/* + * Context: task, can sleep + */ void qla83xx_idc_unlock(scsi_qla_host_t *base_vha, uint16_t requester_id) { @@ -6269,6 +6262,8 @@ qla83xx_idc_unlock(scsi_qla_host_t *base_vha, uint16_t requester_id) uint32_t data; struct qla_hw_data *ha = base_vha->hw; + might_sleep(); + /* IDC-unlock implementation using driver-unlock/lock-id * remote registers */ @@ -6284,7 +6279,7 @@ retry_unlock: /* SV: XXX: IDC unlock retrying needed here? */ /* Retry for IDC-unlock */ - qla83xx_wait_logic(); + msleep(QLA83XX_WAIT_LOGIC_MS); retry++; ql_dbg(ql_dbg_p3p, base_vha, 0xb064, "Failed to release IDC lock, retrying=%d\n", retry); @@ -6292,7 +6287,7 @@ retry_unlock: } } else if (retry < 10) { /* Retry for IDC-unlock */ - qla83xx_wait_logic(); + msleep(QLA83XX_WAIT_LOGIC_MS); retry++; ql_dbg(ql_dbg_p3p, base_vha, 0xb065, "Failed to read drv-lockid, retrying=%d\n", retry); @@ -6308,7 +6303,7 @@ retry_unlock2: if (qla83xx_access_control(base_vha, options, 0, 0, NULL)) { if (retry < 10) { /* Retry for IDC-unlock */ - qla83xx_wait_logic(); + msleep(QLA83XX_WAIT_LOGIC_MS); retry++; ql_dbg(ql_dbg_p3p, base_vha, 0xb066, "Failed to release IDC lock, retrying=%d\n", retry); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 0f92e9a044dc..f771fabcba59 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -2634,14 +2634,14 @@ qla28xx_extract_sfub_and_verify(struct scsi_qla_host *vha, uint32_t *buf, sizeof(struct secure_flash_update_block)); for (i = 0; i < (sizeof(struct secure_flash_update_block) >> 2); i++) - check_sum += p[i]; + check_sum += le32_to_cpu(p[i]); check_sum = (~check_sum) + 1; - if (check_sum != p[i]) { + if (check_sum != le32_to_cpu(p[i])) { ql_log(ql_log_warn, vha, 0x7097, "SFUB checksum failed, 0x%x, 0x%x\n", - check_sum, p[i]); + check_sum, le32_to_cpu(p[i])); return QLA_COMMAND_ERROR; } @@ -2721,7 +2721,7 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, if (ha->flags.secure_adapter && region.attribute) { ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, - "Region %x is secure\n", region.code); + "Region %x is secure\n", le16_to_cpu(region.code)); switch (le16_to_cpu(region.code)) { case FLT_REG_FW: @@ -2775,7 +2775,7 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, default: ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, "Secure region %x not supported\n", - region.code); + le16_to_cpu(region.code)); rval = QLA_COMMAND_ERROR; goto done; } diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index a27a625839e6..0d09480b66cd 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1273,7 +1273,7 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) qla24xx_chk_fcp_state(sess); - ql_dbg(ql_dbg_disc, sess->vha, 0xe001, + ql_dbg(ql_log_warn, sess->vha, 0xe001, "Scheduling sess %p for deletion %8phC\n", sess, sess->port_name); @@ -2083,6 +2083,7 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, struct qla_hw_data *ha = vha->hw; struct qla_tgt_mgmt_cmd *mcmd; struct qla_qpair_hint *h = &vha->vha_tgt.qla_tgt->qphints[0]; + struct qla_tgt_cmd *abort_cmd; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f, "qla_target(%d): task abort (tag=%d)\n", @@ -2110,17 +2111,17 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, */ mcmd->se_cmd.cpuid = h->cpuid; - if (ha->tgt.tgt_ops->find_cmd_by_tag) { - struct qla_tgt_cmd *abort_cmd; - - abort_cmd = ha->tgt.tgt_ops->find_cmd_by_tag(sess, + abort_cmd = ha->tgt.tgt_ops->find_cmd_by_tag(sess, le32_to_cpu(abts->exchange_addr_to_abort)); - if (abort_cmd && abort_cmd->qpair) { - mcmd->qpair = abort_cmd->qpair; - mcmd->se_cmd.cpuid = abort_cmd->se_cmd.cpuid; - mcmd->abort_io_attr = abort_cmd->atio.u.isp24.attr; - mcmd->flags = QLA24XX_MGMT_ABORT_IO_ATTR_VALID; - } + if (!abort_cmd) + return -EIO; + mcmd->unpacked_lun = abort_cmd->se_cmd.orig_fe_lun; + + if (abort_cmd->qpair) { + mcmd->qpair = abort_cmd->qpair; + mcmd->se_cmd.cpuid = abort_cmd->se_cmd.cpuid; + mcmd->abort_io_attr = abort_cmd->atio.u.isp24.attr; + mcmd->flags = QLA24XX_MGMT_ABORT_IO_ATTR_VALID; } INIT_WORK(&mcmd->work, qlt_do_tmr_work); @@ -4291,6 +4292,7 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, cmd->cmd_type = TYPE_TGT_CMD; memcpy(&cmd->atio, atio, sizeof(*atio)); + INIT_LIST_HEAD(&cmd->sess_cmd_list); cmd->state = QLA_TGT_STATE_NEW; cmd->tgt = vha->vha_tgt.qla_tgt; qlt_incr_num_pend_cmds(vha); diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 1cff7c69d448..10e5e6c8087d 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -856,6 +856,7 @@ struct qla_tgt_cmd { uint8_t cmd_type; uint8_t pad[7]; struct se_cmd se_cmd; + struct list_head sess_cmd_list; struct fc_port *sess; struct qla_qpair *qpair; uint32_t reset_count; diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index bd8623ee156a..26c13a953b97 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -928,7 +928,8 @@ qla27xx_template_checksum(void *p, ulong size) static inline int qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp) { - return qla27xx_template_checksum(tmp, tmp->template_size) == 0; + return qla27xx_template_checksum(tmp, + le32_to_cpu(tmp->template_size)) == 0; } static inline int @@ -944,7 +945,7 @@ qla27xx_execute_fwdt_template(struct scsi_qla_host *vha, ulong len = 0; if (qla27xx_fwdt_template_valid(tmp)) { - len = tmp->template_size; + len = le32_to_cpu(tmp->template_size); tmp = memcpy(buf, tmp, len); ql27xx_edit_template(vha, tmp); qla27xx_walk_template(vha, tmp, buf, &len); @@ -960,7 +961,7 @@ qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha, void *p) ulong len = 0; if (qla27xx_fwdt_template_valid(tmp)) { - len = tmp->template_size; + len = le32_to_cpu(tmp->template_size); qla27xx_walk_template(vha, tmp, NULL, &len); } @@ -972,7 +973,7 @@ qla27xx_fwdt_template_size(void *p) { struct qla27xx_fwdt_template *tmp = p; - return tmp->template_size; + return le32_to_cpu(tmp->template_size); } int diff --git a/drivers/scsi/qla2xxx/qla_tmpl.h b/drivers/scsi/qla2xxx/qla_tmpl.h index c47184db5081..6e0987edfceb 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.h +++ b/drivers/scsi/qla2xxx/qla_tmpl.h @@ -12,7 +12,7 @@ struct __packed qla27xx_fwdt_template { __le32 template_type; __le32 entry_offset; - uint32_t template_size; + __le32 template_size; uint32_t count; /* borrow field for running/residual count */ __le32 entry_count; diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index c2d4da52f4a9..ccec858875dd 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -6,9 +6,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.02.00.103-k" +#define QLA2XXX_VERSION "10.02.00.104-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 2 #define QLA_DRIVER_PATCH_VER 0 -#define QLA_DRIVER_BETA_VER 103 +#define QLA_DRIVER_BETA_VER 104 diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 61017acd3458..b55fc768a2a7 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -255,6 +255,7 @@ static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) static void tcm_qla2xxx_complete_free(struct work_struct *work) { struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); + unsigned long flags; cmd->cmd_in_wq = 0; @@ -265,6 +266,10 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work) cmd->trc_flags |= TRC_CMD_FREE; cmd->cmd_sent_to_fw = 0; + spin_lock_irqsave(&cmd->sess->sess_cmd_lock, flags); + list_del_init(&cmd->sess_cmd_list); + spin_unlock_irqrestore(&cmd->sess->sess_cmd_lock, flags); + transport_generic_free_cmd(&cmd->se_cmd, 0); } @@ -363,15 +368,10 @@ static void tcm_qla2xxx_put_sess(struct fc_port *sess) static void tcm_qla2xxx_close_session(struct se_session *se_sess) { struct fc_port *sess = se_sess->fabric_sess_ptr; - struct scsi_qla_host *vha; - unsigned long flags; BUG_ON(!sess); - vha = sess->vha; - spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); - target_sess_cmd_list_set_waiting(se_sess); - spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + target_stop_session(se_sess); sess->explicit_logout = 1; tcm_qla2xxx_put_sess(sess); @@ -451,13 +451,14 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, struct se_portal_group *se_tpg; struct tcm_qla2xxx_tpg *tpg; #endif - int flags = TARGET_SCF_ACK_KREF; + int target_flags = TARGET_SCF_ACK_KREF; + unsigned long flags; if (bidi) - flags |= TARGET_SCF_BIDI_OP; + target_flags |= TARGET_SCF_BIDI_OP; if (se_cmd->cpuid != WORK_CPU_UNBOUND) - flags |= TARGET_SCF_USE_CPUID; + target_flags |= TARGET_SCF_USE_CPUID; sess = cmd->sess; if (!sess) { @@ -479,11 +480,15 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, return 0; } #endif - cmd->qpair->tgt_counters.qla_core_sbt_cmd++; + + spin_lock_irqsave(&sess->sess_cmd_lock, flags); + list_add_tail(&cmd->sess_cmd_list, &sess->sess_cmd_list); + spin_unlock_irqrestore(&sess->sess_cmd_lock, flags); + return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], - cmd->unpacked_lun, data_length, fcp_task_attr, - data_dir, flags); + cmd->unpacked_lun, data_length, fcp_task_attr, + data_dir, target_flags); } static void tcm_qla2xxx_handle_data_work(struct work_struct *work) @@ -574,13 +579,11 @@ static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, u64 lun, struct fc_port *sess = mcmd->sess; struct se_cmd *se_cmd = &mcmd->se_cmd; int transl_tmr_func = 0; - int flags = TARGET_SCF_ACK_KREF; switch (tmr_func) { case QLA_TGT_ABTS: pr_debug("%ld: ABTS received\n", sess->vha->host_no); transl_tmr_func = TMR_ABORT_TASK; - flags |= TARGET_SCF_LOOKUP_LUN_FROM_TAG; break; case QLA_TGT_2G_ABORT_TASK: pr_debug("%ld: 2G Abort Task received\n", sess->vha->host_no); @@ -613,31 +616,26 @@ static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, u64 lun, } return target_submit_tmr(se_cmd, sess->se_sess, NULL, lun, mcmd, - transl_tmr_func, GFP_ATOMIC, tag, flags); + transl_tmr_func, GFP_ATOMIC, tag, TARGET_SCF_ACK_KREF); } static struct qla_tgt_cmd *tcm_qla2xxx_find_cmd_by_tag(struct fc_port *sess, uint64_t tag) { - struct qla_tgt_cmd *cmd = NULL; - struct se_cmd *secmd; + struct qla_tgt_cmd *cmd; unsigned long flags; if (!sess->se_sess) return NULL; - spin_lock_irqsave(&sess->se_sess->sess_cmd_lock, flags); - list_for_each_entry(secmd, &sess->se_sess->sess_cmd_list, se_cmd_list) { - /* skip task management functions, including tmr->task_cmd */ - if (secmd->se_cmd_flags & SCF_SCSI_TMR_CDB) - continue; - - if (secmd->tag == tag) { - cmd = container_of(secmd, struct qla_tgt_cmd, se_cmd); - break; - } + spin_lock_irqsave(&sess->sess_cmd_lock, flags); + list_for_each_entry(cmd, &sess->sess_cmd_list, sess_cmd_list) { + if (cmd->se_cmd.tag == tag) + goto done; } - spin_unlock_irqrestore(&sess->se_sess->sess_cmd_lock, flags); + cmd = NULL; +done: + spin_unlock_irqrestore(&sess->sess_cmd_lock, flags); return cmd; } @@ -767,11 +765,19 @@ static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd) static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd) { - struct qla_tgt_cmd *cmd = container_of(se_cmd, - struct qla_tgt_cmd, se_cmd); + struct qla_tgt_cmd *cmd; + unsigned long flags; - if (qlt_abort_cmd(cmd)) + if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) return; + + cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); + + spin_lock_irqsave(&cmd->sess->sess_cmd_lock, flags); + list_del_init(&cmd->sess_cmd_list); + spin_unlock_irqrestore(&cmd->sess->sess_cmd_lock, flags); + + qlt_abort_cmd(cmd); } static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *, @@ -820,7 +826,7 @@ static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct fc_port *sess) static void tcm_qla2xxx_shutdown_sess(struct fc_port *sess) { - target_sess_cmd_list_set_waiting(sess->se_sess); + target_stop_session(sess->se_sess); } static int tcm_qla2xxx_init_nodeacl(struct se_node_acl *se_nacl, @@ -1394,8 +1400,6 @@ static void tcm_qla2xxx_free_session(struct fc_port *sess) struct se_session *se_sess; struct tcm_qla2xxx_lport *lport; - BUG_ON(in_interrupt()); - se_sess = sess->se_sess; if (!se_sess) { pr_err("struct fc_port->se_sess is NULL\n"); diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index f5b382ed0a1b..031569c496e5 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -435,9 +435,9 @@ struct isp_operations { void (*wr_reg_direct) (struct scsi_qla_host *, ulong, uint32_t); int (*rd_reg_indirect) (struct scsi_qla_host *, uint32_t, uint32_t *); int (*wr_reg_indirect) (struct scsi_qla_host *, uint32_t, uint32_t); - int (*idc_lock) (struct scsi_qla_host *); + int (*idc_lock) (struct scsi_qla_host *); /* Context: task, can sleep */ void (*idc_unlock) (struct scsi_qla_host *); - void (*rom_lock_recovery) (struct scsi_qla_host *); + void (*rom_lock_recovery) (struct scsi_qla_host *); /* Context: task, can sleep */ void (*queue_mailbox_command) (struct scsi_qla_host *, uint32_t *, int); void (*process_mailbox_interrupt) (struct scsi_qla_host *, int); }; diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index b8f02210aeb0..ea60057b2e20 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -114,7 +114,6 @@ irqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id); void qla4_82xx_queue_iocb(struct scsi_qla_host *ha); void qla4_82xx_complete_iocb(struct scsi_qla_host *ha); -int qla4_82xx_crb_win_lock(struct scsi_qla_host *); void qla4_82xx_crb_win_unlock(struct scsi_qla_host *); int qla4_82xx_pci_get_crb_addr_2M(struct scsi_qla_host *, ulong *); void qla4_82xx_wr_32(struct scsi_qla_host *, ulong, u32); diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index f1767b21076f..e6e35e6958f6 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -375,6 +375,35 @@ qla4_82xx_pci_set_crbwindow_2M(struct scsi_qla_host *ha, ulong *off) *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase; } +#define CRB_WIN_LOCK_TIMEOUT 100000000 + +/* + * Context: atomic + */ +static int qla4_82xx_crb_win_lock(struct scsi_qla_host *ha) +{ + int done = 0, timeout = 0; + + while (!done) { + /* acquire semaphore3 from PCI HW block */ + done = qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); + if (done == 1) + break; + if (timeout >= CRB_WIN_LOCK_TIMEOUT) + return -1; + + timeout++; + udelay(10); + } + qla4_82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->func_num); + return 0; +} + +void qla4_82xx_crb_win_unlock(struct scsi_qla_host *ha) +{ + qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); +} + void qla4_82xx_wr_32(struct scsi_qla_host *ha, ulong off, u32 data) { @@ -475,40 +504,6 @@ int qla4_82xx_md_wr_32(struct scsi_qla_host *ha, uint32_t off, uint32_t data) return rval; } -#define CRB_WIN_LOCK_TIMEOUT 100000000 - -int qla4_82xx_crb_win_lock(struct scsi_qla_host *ha) -{ - int i; - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore3 from PCI HW block */ - done = qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); - if (done == 1) - break; - if (timeout >= CRB_WIN_LOCK_TIMEOUT) - return -1; - - timeout++; - - /* Yield CPU */ - if (!in_interrupt()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); /*This a nop instr on i386*/ - } - } - qla4_82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->func_num); - return 0; -} - -void qla4_82xx_crb_win_unlock(struct scsi_qla_host *ha) -{ - qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); -} - #define IDC_LOCK_TIMEOUT 100000000 /** @@ -517,12 +512,15 @@ void qla4_82xx_crb_win_unlock(struct scsi_qla_host *ha) * * General purpose lock used to synchronize access to * CRB_DEV_STATE, CRB_DEV_REF_COUNT, etc. + * + * Context: task, can sleep **/ int qla4_82xx_idc_lock(struct scsi_qla_host *ha) { - int i; int done = 0, timeout = 0; + might_sleep(); + while (!done) { /* acquire semaphore5 from PCI HW block */ done = qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK)); @@ -532,14 +530,7 @@ int qla4_82xx_idc_lock(struct scsi_qla_host *ha) return -1; timeout++; - - /* Yield CPU */ - if (!in_interrupt()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); /*This a nop instr on i386*/ - } + msleep(100); } return 0; } @@ -880,15 +871,18 @@ qla4_82xx_decode_crb_addr(unsigned long addr) static long rom_max_timeout = 100; static long qla4_82xx_rom_lock_timeout = 100; +/* + * Context: task, can_sleep + */ static int qla4_82xx_rom_lock(struct scsi_qla_host *ha) { - int i; int done = 0, timeout = 0; + might_sleep(); + while (!done) { /* acquire semaphore2 from PCI HW block */ - done = qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK)); if (done == 1) break; @@ -896,14 +890,7 @@ qla4_82xx_rom_lock(struct scsi_qla_host *ha) return -1; timeout++; - - /* Yield CPU */ - if (!in_interrupt()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); /*This a nop instr on i386*/ - } + msleep(20); } qla4_82xx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ROM_LOCK_DRIVER); return 0; @@ -1780,7 +1767,7 @@ qla4_82xx_start_firmware(struct scsi_qla_host *ha, uint32_t image_start) int qla4_82xx_try_start_fw(struct scsi_qla_host *ha) { - int rval = QLA_ERROR; + int rval; /* * FW Load priority: diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 2c23b692e318..a4b014e1cd8c 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -685,7 +685,6 @@ static int qla4xxx_get_chap_by_index(struct scsi_qla_host *ha, if (!ha->chap_list) { ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n"); - rval = QLA_ERROR; goto exit_get_chap; } @@ -697,14 +696,12 @@ static int qla4xxx_get_chap_by_index(struct scsi_qla_host *ha, if (chap_index > max_chap_entries) { ql4_printk(KERN_ERR, ha, "Invalid Chap index\n"); - rval = QLA_ERROR; goto exit_get_chap; } *chap_entry = (struct ql4_chap_table *)ha->chap_list + chap_index; if ((*chap_entry)->cookie != __constant_cpu_to_le16(CHAP_VALID_COOKIE)) { - rval = QLA_ERROR; *chap_entry = NULL; } else { rval = QLA_SUCCESS; diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index ba84244c1b4f..d92cec12454c 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -559,7 +559,8 @@ static int scsi_dev_info_list_add_str(char *dev_list) } /** - * get_device_flags - get device specific flags from the dynamic device list. + * scsi_get_device_flags - get device specific flags from the dynamic + * device list. * @sdev: &scsi_device to get flags for * @vendor: vendor name * @model: model name diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 03c6d0620bfd..4848ae3c7b56 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -766,6 +766,9 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) case 0x24: /* depopulation in progress */ action = ACTION_DELAYED_RETRY; break; + case 0x0a: /* ALUA state transition */ + blk_stat = BLK_STS_AGAIN; + fallthrough; default: action = ACTION_FAIL; break; @@ -1455,7 +1458,7 @@ static void scsi_softirq_done(struct request *rq) } /** - * scsi_dispatch_command - Dispatch a command to the low-level driver. + * scsi_dispatch_cmd - Dispatch a command to the low-level driver. * @cmd: command block we are dispatching. * * Return: nonzero return request was rejected and device's queue needs to be @@ -1706,6 +1709,11 @@ out_put_budget: if (scsi_device_blocked(sdev)) ret = BLK_STS_DEV_RESOURCE; break; + case BLK_STS_AGAIN: + scsi_req(req)->result = DID_BUS_BUSY << 16; + if (req->rq_flags & RQF_DONTPREP) + scsi_mq_uninit_cmd(cmd); + break; default: if (unlikely(!scsi_device_online(sdev))) scsi_req(req)->result = DID_NO_CONNECT << 16; @@ -2334,7 +2342,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) EXPORT_SYMBOL(scsi_device_set_state); /** - * sdev_evt_emit - emit a single SCSI device uevent + * scsi_evt_emit - emit a single SCSI device uevent * @sdev: associated SCSI device * @evt: event to emit * @@ -2382,7 +2390,7 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt) } /** - * sdev_evt_thread - send a uevent for each scsi event + * scsi_evt_thread - send a uevent for each scsi event * @work: work struct for scsi_device * * Dispatch queued events to their associated scsi_device kobjects @@ -2948,6 +2956,78 @@ void sdev_enable_disk_events(struct scsi_device *sdev) } EXPORT_SYMBOL(sdev_enable_disk_events); +static unsigned char designator_prio(const unsigned char *d) +{ + if (d[1] & 0x30) + /* not associated with LUN */ + return 0; + + if (d[3] == 0) + /* invalid length */ + return 0; + + /* + * Order of preference for lun descriptor: + * - SCSI name string + * - NAA IEEE Registered Extended + * - EUI-64 based 16-byte + * - EUI-64 based 12-byte + * - NAA IEEE Registered + * - NAA IEEE Extended + * - EUI-64 based 8-byte + * - SCSI name string (truncated) + * - T10 Vendor ID + * as longer descriptors reduce the likelyhood + * of identification clashes. + */ + + switch (d[1] & 0xf) { + case 8: + /* SCSI name string, variable-length UTF-8 */ + return 9; + case 3: + switch (d[4] >> 4) { + case 6: + /* NAA registered extended */ + return 8; + case 5: + /* NAA registered */ + return 5; + case 4: + /* NAA extended */ + return 4; + case 3: + /* NAA locally assigned */ + return 1; + default: + break; + } + break; + case 2: + switch (d[3]) { + case 16: + /* EUI64-based, 16 byte */ + return 7; + case 12: + /* EUI64-based, 12 byte */ + return 6; + case 8: + /* EUI64-based, 8 byte */ + return 3; + default: + break; + } + break; + case 1: + /* T10 vendor ID */ + return 1; + default: + break; + } + + return 0; +} + /** * scsi_vpd_lun_id - return a unique device identification * @sdev: SCSI device @@ -2964,7 +3044,7 @@ EXPORT_SYMBOL(sdev_enable_disk_events); */ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len) { - u8 cur_id_type = 0xff; + u8 cur_id_prio = 0; u8 cur_id_size = 0; const unsigned char *d, *cur_id_str; const struct scsi_vpd *vpd_pg83; @@ -2977,20 +3057,6 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len) return -ENXIO; } - /* - * Look for the correct descriptor. - * Order of preference for lun descriptor: - * - SCSI name string - * - NAA IEEE Registered Extended - * - EUI-64 based 16-byte - * - EUI-64 based 12-byte - * - NAA IEEE Registered - * - NAA IEEE Extended - * - T10 Vendor ID - * as longer descriptors reduce the likelyhood - * of identification clashes. - */ - /* The id string must be at least 20 bytes + terminating NULL byte */ if (id_len < 21) { rcu_read_unlock(); @@ -2998,39 +3064,32 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len) } memset(id, 0, id_len); - d = vpd_pg83->data + 4; - while (d < vpd_pg83->data + vpd_pg83->len) { - /* Skip designators not referring to the LUN */ - if ((d[1] & 0x30) != 0x00) - goto next_desig; + for (d = vpd_pg83->data + 4; + d < vpd_pg83->data + vpd_pg83->len; + d += d[3] + 4) { + u8 prio = designator_prio(d); + + if (prio == 0 || cur_id_prio > prio) + continue; switch (d[1] & 0xf) { case 0x1: /* T10 Vendor ID */ if (cur_id_size > d[3]) break; - /* Prefer anything */ - if (cur_id_type > 0x01 && cur_id_type != 0xff) - break; + cur_id_prio = prio; cur_id_size = d[3]; if (cur_id_size + 4 > id_len) cur_id_size = id_len - 4; cur_id_str = d + 4; - cur_id_type = d[1] & 0xf; id_size = snprintf(id, id_len, "t10.%*pE", cur_id_size, cur_id_str); break; case 0x2: /* EUI-64 */ - if (cur_id_size > d[3]) - break; - /* Prefer NAA IEEE Registered Extended */ - if (cur_id_type == 0x3 && - cur_id_size == d[3]) - break; + cur_id_prio = prio; cur_id_size = d[3]; cur_id_str = d + 4; - cur_id_type = d[1] & 0xf; switch (cur_id_size) { case 8: id_size = snprintf(id, id_len, @@ -3048,17 +3107,14 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len) cur_id_str); break; default: - cur_id_size = 0; break; } break; case 0x3: /* NAA */ - if (cur_id_size > d[3]) - break; + cur_id_prio = prio; cur_id_size = d[3]; cur_id_str = d + 4; - cur_id_type = d[1] & 0xf; switch (cur_id_size) { case 8: id_size = snprintf(id, id_len, @@ -3071,32 +3127,29 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len) cur_id_str); break; default: - cur_id_size = 0; break; } break; case 0x8: /* SCSI name string */ - if (cur_id_size + 4 > d[3]) + if (cur_id_size > d[3]) break; /* Prefer others for truncated descriptor */ - if (cur_id_size && d[3] > id_len) - break; + if (d[3] > id_len) { + prio = 2; + if (cur_id_prio > prio) + break; + } + cur_id_prio = prio; cur_id_size = id_size = d[3]; cur_id_str = d + 4; - cur_id_type = d[1] & 0xf; if (cur_id_size >= id_len) cur_id_size = id_len - 1; memcpy(id, cur_id_str, cur_id_size); - /* Decrease priority for truncated descriptor */ - if (cur_id_size != id_size) - cur_id_size = 6; break; default: break; } -next_desig: - d += d[3] + 4; } rcu_read_unlock(); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index d6e344fa33ad..b6378c8ca783 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -370,7 +370,7 @@ static DEVICE_ATTR(eh_deadline, S_IRUGO | S_IWUSR, show_shost_eh_deadline, store shost_rd_attr(unique_id, "%u\n"); shost_rd_attr(cmd_per_lun, "%hd\n"); -shost_rd_attr(can_queue, "%hd\n"); +shost_rd_attr(can_queue, "%d\n"); shost_rd_attr(sg_tablesize, "%hu\n"); shost_rd_attr(sg_prot_tablesize, "%hu\n"); shost_rd_attr(unchecked_isa_dma, "%d\n"); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 2ff7f06203da..a926e8f9e56e 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -22,6 +22,7 @@ #include <net/netlink.h> #include <scsi/scsi_netlink_fc.h> #include <scsi/scsi_bsg_fc.h> +#include <uapi/scsi/fc/fc_els.h> #include "scsi_priv.h" static int fc_queue_work(struct Scsi_Host *, struct work_struct *); @@ -33,6 +34,11 @@ static int fc_bsg_hostadd(struct Scsi_Host *, struct fc_host_attrs *); static int fc_bsg_rportadd(struct Scsi_Host *, struct fc_rport *); static void fc_bsg_remove(struct request_queue *); static void fc_bsg_goose_queue(struct fc_rport *); +static void fc_li_stats_update(struct fc_fn_li_desc *li_desc, + struct fc_fpin_stats *stats); +static void fc_delivery_stats_update(u32 reason_code, + struct fc_fpin_stats *stats); +static void fc_cn_stats_update(u16 event_type, struct fc_fpin_stats *stats); /* * Module Parameters @@ -419,6 +425,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, fc_host->fabric_name = -1; memset(fc_host->symbolic_name, 0, sizeof(fc_host->symbolic_name)); memset(fc_host->system_hostname, 0, sizeof(fc_host->system_hostname)); + memset(&fc_host->fpin_stats, 0, sizeof(fc_host->fpin_stats)); fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN; @@ -629,7 +636,263 @@ fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, EXPORT_SYMBOL(fc_host_post_vendor_event); /** - * fc_host_rcv_fpin - routine to process a received FPIN. + * fc_find_rport_by_wwpn - find the fc_rport pointer for a given wwpn + * @shost: host the fc_rport is associated with + * @wwpn: wwpn of the fc_rport device + * + * Notes: + * This routine assumes no locks are held on entry. + */ +struct fc_rport * +fc_find_rport_by_wwpn(struct Scsi_Host *shost, u64 wwpn) +{ + struct fc_rport *rport; + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + + list_for_each_entry(rport, &fc_host_rports(shost), peers) { + if (rport->port_state != FC_PORTSTATE_ONLINE) + continue; + + if (rport->port_name == wwpn) { + spin_unlock_irqrestore(shost->host_lock, flags); + return rport; + } + } + + spin_unlock_irqrestore(shost->host_lock, flags); + return NULL; +} +EXPORT_SYMBOL(fc_find_rport_by_wwpn); + +static void +fc_li_stats_update(struct fc_fn_li_desc *li_desc, + struct fc_fpin_stats *stats) +{ + stats->li += be32_to_cpu(li_desc->event_count); + switch (be16_to_cpu(li_desc->event_type)) { + case FPIN_LI_UNKNOWN: + stats->li_failure_unknown += + be32_to_cpu(li_desc->event_count); + break; + case FPIN_LI_LINK_FAILURE: + stats->li_link_failure_count += + be32_to_cpu(li_desc->event_count); + break; + case FPIN_LI_LOSS_OF_SYNC: + stats->li_loss_of_sync_count += + be32_to_cpu(li_desc->event_count); + break; + case FPIN_LI_LOSS_OF_SIG: + stats->li_loss_of_signals_count += + be32_to_cpu(li_desc->event_count); + break; + case FPIN_LI_PRIM_SEQ_ERR: + stats->li_prim_seq_err_count += + be32_to_cpu(li_desc->event_count); + break; + case FPIN_LI_INVALID_TX_WD: + stats->li_invalid_tx_word_count += + be32_to_cpu(li_desc->event_count); + break; + case FPIN_LI_INVALID_CRC: + stats->li_invalid_crc_count += + be32_to_cpu(li_desc->event_count); + break; + case FPIN_LI_DEVICE_SPEC: + stats->li_device_specific += + be32_to_cpu(li_desc->event_count); + break; + } +} + +static void +fc_delivery_stats_update(u32 reason_code, struct fc_fpin_stats *stats) +{ + stats->dn++; + switch (reason_code) { + case FPIN_DELI_UNKNOWN: + stats->dn_unknown++; + break; + case FPIN_DELI_TIMEOUT: + stats->dn_timeout++; + break; + case FPIN_DELI_UNABLE_TO_ROUTE: + stats->dn_unable_to_route++; + break; + case FPIN_DELI_DEVICE_SPEC: + stats->dn_device_specific++; + break; + } +} + +static void +fc_cn_stats_update(u16 event_type, struct fc_fpin_stats *stats) +{ + stats->cn++; + switch (event_type) { + case FPIN_CONGN_CLEAR: + stats->cn_clear++; + break; + case FPIN_CONGN_LOST_CREDIT: + stats->cn_lost_credit++; + break; + case FPIN_CONGN_CREDIT_STALL: + stats->cn_credit_stall++; + break; + case FPIN_CONGN_OVERSUBSCRIPTION: + stats->cn_oversubscription++; + break; + case FPIN_CONGN_DEVICE_SPEC: + stats->cn_device_specific++; + } +} + +/* + * fc_fpin_li_stats_update - routine to update Link Integrity + * event statistics. + * @shost: host the FPIN was received on + * @tlv: pointer to link integrity descriptor + * + */ +static void +fc_fpin_li_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv) +{ + u8 i; + struct fc_rport *rport = NULL; + struct fc_rport *attach_rport = NULL; + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); + struct fc_fn_li_desc *li_desc = (struct fc_fn_li_desc *)tlv; + u64 wwpn; + + rport = fc_find_rport_by_wwpn(shost, + be64_to_cpu(li_desc->attached_wwpn)); + if (rport && + (rport->roles & FC_PORT_ROLE_FCP_TARGET || + rport->roles & FC_PORT_ROLE_NVME_TARGET)) { + attach_rport = rport; + fc_li_stats_update(li_desc, &attach_rport->fpin_stats); + } + + if (be32_to_cpu(li_desc->pname_count) > 0) { + for (i = 0; + i < be32_to_cpu(li_desc->pname_count); + i++) { + wwpn = be64_to_cpu(li_desc->pname_list[i]); + rport = fc_find_rport_by_wwpn(shost, wwpn); + if (rport && + (rport->roles & FC_PORT_ROLE_FCP_TARGET || + rport->roles & FC_PORT_ROLE_NVME_TARGET)) { + if (rport == attach_rport) + continue; + fc_li_stats_update(li_desc, + &rport->fpin_stats); + } + } + } + + if (fc_host->port_name == be64_to_cpu(li_desc->attached_wwpn)) + fc_li_stats_update(li_desc, &fc_host->fpin_stats); +} + +/* + * fc_fpin_delivery_stats_update - routine to update Delivery Notification + * event statistics. + * @shost: host the FPIN was received on + * @tlv: pointer to delivery descriptor + * + */ +static void +fc_fpin_delivery_stats_update(struct Scsi_Host *shost, + struct fc_tlv_desc *tlv) +{ + struct fc_rport *rport = NULL; + struct fc_rport *attach_rport = NULL; + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); + struct fc_fn_deli_desc *dn_desc = (struct fc_fn_deli_desc *)tlv; + u32 reason_code = be32_to_cpu(dn_desc->deli_reason_code); + + rport = fc_find_rport_by_wwpn(shost, + be64_to_cpu(dn_desc->attached_wwpn)); + if (rport && + (rport->roles & FC_PORT_ROLE_FCP_TARGET || + rport->roles & FC_PORT_ROLE_NVME_TARGET)) { + attach_rport = rport; + fc_delivery_stats_update(reason_code, + &attach_rport->fpin_stats); + } + + if (fc_host->port_name == be64_to_cpu(dn_desc->attached_wwpn)) + fc_delivery_stats_update(reason_code, &fc_host->fpin_stats); +} + +/* + * fc_fpin_peer_congn_stats_update - routine to update Peer Congestion + * event statistics. + * @shost: host the FPIN was received on + * @tlv: pointer to peer congestion descriptor + * + */ +static void +fc_fpin_peer_congn_stats_update(struct Scsi_Host *shost, + struct fc_tlv_desc *tlv) +{ + u8 i; + struct fc_rport *rport = NULL; + struct fc_rport *attach_rport = NULL; + struct fc_fn_peer_congn_desc *pc_desc = + (struct fc_fn_peer_congn_desc *)tlv; + u16 event_type = be16_to_cpu(pc_desc->event_type); + u64 wwpn; + + rport = fc_find_rport_by_wwpn(shost, + be64_to_cpu(pc_desc->attached_wwpn)); + if (rport && + (rport->roles & FC_PORT_ROLE_FCP_TARGET || + rport->roles & FC_PORT_ROLE_NVME_TARGET)) { + attach_rport = rport; + fc_cn_stats_update(event_type, &attach_rport->fpin_stats); + } + + if (be32_to_cpu(pc_desc->pname_count) > 0) { + for (i = 0; + i < be32_to_cpu(pc_desc->pname_count); + i++) { + wwpn = be64_to_cpu(pc_desc->pname_list[i]); + rport = fc_find_rport_by_wwpn(shost, wwpn); + if (rport && + (rport->roles & FC_PORT_ROLE_FCP_TARGET || + rport->roles & FC_PORT_ROLE_NVME_TARGET)) { + if (rport == attach_rport) + continue; + fc_cn_stats_update(event_type, + &rport->fpin_stats); + } + } + } +} + +/* + * fc_fpin_congn_stats_update - routine to update Congestion + * event statistics. + * @shost: host the FPIN was received on + * @tlv: pointer to congestion descriptor + * + */ +static void +fc_fpin_congn_stats_update(struct Scsi_Host *shost, + struct fc_tlv_desc *tlv) +{ + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); + struct fc_fn_congn_desc *congn = (struct fc_fn_congn_desc *)tlv; + + fc_cn_stats_update(be16_to_cpu(congn->event_type), + &fc_host->fpin_stats); +} + +/** + * fc_host_fpin_rcv - routine to process a received FPIN. * @shost: host the FPIN was received on * @fpin_len: length of FPIN payload, in bytes * @fpin_buf: pointer to FPIN payload @@ -640,6 +903,38 @@ EXPORT_SYMBOL(fc_host_post_vendor_event); void fc_host_fpin_rcv(struct Scsi_Host *shost, u32 fpin_len, char *fpin_buf) { + struct fc_els_fpin *fpin = (struct fc_els_fpin *)fpin_buf; + struct fc_tlv_desc *tlv; + u32 desc_cnt = 0, bytes_remain; + u32 dtag; + + /* Update Statistics */ + tlv = (struct fc_tlv_desc *)&fpin->fpin_desc[0]; + bytes_remain = fpin_len - offsetof(struct fc_els_fpin, fpin_desc); + bytes_remain = min_t(u32, bytes_remain, be32_to_cpu(fpin->desc_len)); + + while (bytes_remain >= FC_TLV_DESC_HDR_SZ && + bytes_remain >= FC_TLV_DESC_SZ_FROM_LENGTH(tlv)) { + dtag = be32_to_cpu(tlv->desc_tag); + switch (dtag) { + case ELS_DTAG_LNK_INTEGRITY: + fc_fpin_li_stats_update(shost, tlv); + break; + case ELS_DTAG_DELIVERY: + fc_fpin_delivery_stats_update(shost, tlv); + break; + case ELS_DTAG_PEER_CONGEST: + fc_fpin_peer_congn_stats_update(shost, tlv); + break; + case ELS_DTAG_CONGESTION: + fc_fpin_congn_stats_update(shost, tlv); + } + + desc_cnt++; + bytes_remain -= FC_TLV_DESC_SZ_FROM_LENGTH(tlv); + tlv = fc_tlv_next_desc(tlv); + } + fc_host_post_fc_event(shost, fc_get_event_number(), FCH_EVT_LINK_FPIN, fpin_len, fpin_buf, 0); } @@ -991,6 +1286,67 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev, static FC_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR, show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo); +#define fc_rport_fpin_statistic(name) \ +static ssize_t fc_rport_fpinstat_##name(struct device *cd, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct fc_rport *rport = transport_class_to_rport(cd); \ + \ + return snprintf(buf, 20, "0x%llx\n", rport->fpin_stats.name); \ +} \ +static FC_DEVICE_ATTR(rport, fpin_##name, 0444, fc_rport_fpinstat_##name, NULL) + +fc_rport_fpin_statistic(dn); +fc_rport_fpin_statistic(dn_unknown); +fc_rport_fpin_statistic(dn_timeout); +fc_rport_fpin_statistic(dn_unable_to_route); +fc_rport_fpin_statistic(dn_device_specific); +fc_rport_fpin_statistic(cn); +fc_rport_fpin_statistic(cn_clear); +fc_rport_fpin_statistic(cn_lost_credit); +fc_rport_fpin_statistic(cn_credit_stall); +fc_rport_fpin_statistic(cn_oversubscription); +fc_rport_fpin_statistic(cn_device_specific); +fc_rport_fpin_statistic(li); +fc_rport_fpin_statistic(li_failure_unknown); +fc_rport_fpin_statistic(li_link_failure_count); +fc_rport_fpin_statistic(li_loss_of_sync_count); +fc_rport_fpin_statistic(li_loss_of_signals_count); +fc_rport_fpin_statistic(li_prim_seq_err_count); +fc_rport_fpin_statistic(li_invalid_tx_word_count); +fc_rport_fpin_statistic(li_invalid_crc_count); +fc_rport_fpin_statistic(li_device_specific); + +static struct attribute *fc_rport_statistics_attrs[] = { + &device_attr_rport_fpin_dn.attr, + &device_attr_rport_fpin_dn_unknown.attr, + &device_attr_rport_fpin_dn_timeout.attr, + &device_attr_rport_fpin_dn_unable_to_route.attr, + &device_attr_rport_fpin_dn_device_specific.attr, + &device_attr_rport_fpin_li.attr, + &device_attr_rport_fpin_li_failure_unknown.attr, + &device_attr_rport_fpin_li_link_failure_count.attr, + &device_attr_rport_fpin_li_loss_of_sync_count.attr, + &device_attr_rport_fpin_li_loss_of_signals_count.attr, + &device_attr_rport_fpin_li_prim_seq_err_count.attr, + &device_attr_rport_fpin_li_invalid_tx_word_count.attr, + &device_attr_rport_fpin_li_invalid_crc_count.attr, + &device_attr_rport_fpin_li_device_specific.attr, + &device_attr_rport_fpin_cn.attr, + &device_attr_rport_fpin_cn_clear.attr, + &device_attr_rport_fpin_cn_lost_credit.attr, + &device_attr_rport_fpin_cn_credit_stall.attr, + &device_attr_rport_fpin_cn_oversubscription.attr, + &device_attr_rport_fpin_cn_device_specific.attr, + NULL +}; + +static struct attribute_group fc_rport_statistics_group = { + .name = "statistics", + .attrs = fc_rport_statistics_attrs, +}; + /* * FC SCSI Target Attribute Management @@ -1744,6 +2100,42 @@ fc_host_statistic(fc_xid_not_found); fc_host_statistic(fc_xid_busy); fc_host_statistic(fc_seq_not_found); fc_host_statistic(fc_non_bls_resp); +fc_host_statistic(cn_sig_warn); +fc_host_statistic(cn_sig_alarm); + + +#define fc_host_fpin_statistic(name) \ +static ssize_t fc_host_fpinstat_##name(struct device *cd, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct Scsi_Host *shost = transport_class_to_shost(cd); \ + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); \ + \ + return snprintf(buf, 20, "0x%llx\n", fc_host->fpin_stats.name); \ +} \ +static FC_DEVICE_ATTR(host, fpin_##name, 0444, fc_host_fpinstat_##name, NULL) + +fc_host_fpin_statistic(dn); +fc_host_fpin_statistic(dn_unknown); +fc_host_fpin_statistic(dn_timeout); +fc_host_fpin_statistic(dn_unable_to_route); +fc_host_fpin_statistic(dn_device_specific); +fc_host_fpin_statistic(cn); +fc_host_fpin_statistic(cn_clear); +fc_host_fpin_statistic(cn_lost_credit); +fc_host_fpin_statistic(cn_credit_stall); +fc_host_fpin_statistic(cn_oversubscription); +fc_host_fpin_statistic(cn_device_specific); +fc_host_fpin_statistic(li); +fc_host_fpin_statistic(li_failure_unknown); +fc_host_fpin_statistic(li_link_failure_count); +fc_host_fpin_statistic(li_loss_of_sync_count); +fc_host_fpin_statistic(li_loss_of_signals_count); +fc_host_fpin_statistic(li_prim_seq_err_count); +fc_host_fpin_statistic(li_invalid_tx_word_count); +fc_host_fpin_statistic(li_invalid_crc_count); +fc_host_fpin_statistic(li_device_specific); static ssize_t fc_reset_statistics(struct device *dev, struct device_attribute *attr, @@ -1793,7 +2185,29 @@ static struct attribute *fc_statistics_attrs[] = { &device_attr_host_fc_xid_busy.attr, &device_attr_host_fc_seq_not_found.attr, &device_attr_host_fc_non_bls_resp.attr, + &device_attr_host_cn_sig_warn.attr, + &device_attr_host_cn_sig_alarm.attr, &device_attr_host_reset_statistics.attr, + &device_attr_host_fpin_dn.attr, + &device_attr_host_fpin_dn_unknown.attr, + &device_attr_host_fpin_dn_timeout.attr, + &device_attr_host_fpin_dn_unable_to_route.attr, + &device_attr_host_fpin_dn_device_specific.attr, + &device_attr_host_fpin_li.attr, + &device_attr_host_fpin_li_failure_unknown.attr, + &device_attr_host_fpin_li_link_failure_count.attr, + &device_attr_host_fpin_li_loss_of_sync_count.attr, + &device_attr_host_fpin_li_loss_of_signals_count.attr, + &device_attr_host_fpin_li_prim_seq_err_count.attr, + &device_attr_host_fpin_li_invalid_tx_word_count.attr, + &device_attr_host_fpin_li_invalid_crc_count.attr, + &device_attr_host_fpin_li_device_specific.attr, + &device_attr_host_fpin_cn.attr, + &device_attr_host_fpin_cn_clear.attr, + &device_attr_host_fpin_cn_lost_credit.attr, + &device_attr_host_fpin_cn_credit_stall.attr, + &device_attr_host_fpin_cn_oversubscription.attr, + &device_attr_host_fpin_cn_device_specific.attr, NULL }; @@ -2177,6 +2591,7 @@ fc_attach_transport(struct fc_function_template *ft) i->rport_attr_cont.ac.attrs = &i->rport_attrs[0]; i->rport_attr_cont.ac.class = &fc_rport_class.class; i->rport_attr_cont.ac.match = fc_rport_match; + i->rport_attr_cont.statistics = &fc_rport_statistics_group; transport_container_register(&i->rport_attr_cont); i->vport_attr_cont.ac.attrs = &i->vport_attrs[0]; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 2eb3e4f9375a..2e68c0a87698 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2313,7 +2313,9 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) return conn; release_conn_ref: - put_device(&conn->dev); + device_unregister(&conn->dev); + put_device(&session->dev); + return NULL; release_parent_ref: put_device(&session->dev); free_conn: diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 9d0229656681..c53f456fbd09 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -33,11 +33,11 @@ #define BUILD_TIMESTAMP #endif -#define DRIVER_VERSION "1.2.16-010" +#define DRIVER_VERSION "1.2.16-012" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 2 #define DRIVER_RELEASE 16 -#define DRIVER_REVISION 10 +#define DRIVER_REVISION 12 #define DRIVER_NAME "Microsemi PQI Driver (v" \ DRIVER_VERSION BUILD_TIMESTAMP ")" @@ -345,10 +345,9 @@ static inline void pqi_device_remove_start(struct pqi_scsi_dev *device) device->in_remove = true; } -static inline bool pqi_device_in_remove(struct pqi_ctrl_info *ctrl_info, - struct pqi_scsi_dev *device) +static inline bool pqi_device_in_remove(struct pqi_scsi_dev *device) { - return device->in_remove && !ctrl_info->in_shutdown; + return device->in_remove; } static inline void pqi_ctrl_shutdown_start(struct pqi_ctrl_info *ctrl_info) @@ -5347,8 +5346,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, atomic_inc(&device->scsi_cmds_outstanding); - if (pqi_ctrl_offline(ctrl_info) || pqi_device_in_remove(ctrl_info, - device)) { + if (pqi_ctrl_offline(ctrl_info) || pqi_device_in_remove(device)) { set_host_byte(scmd, DID_NO_CONNECT); pqi_scsi_done(scmd); return 0; @@ -8031,8 +8029,6 @@ static void pqi_pci_remove(struct pci_dev *pci_dev) if (!ctrl_info) return; - ctrl_info->in_shutdown = true; - pqi_remove_ctrl(ctrl_info); } diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c index 999870eb9ed8..c9b00b3368d7 100644 --- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c +++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c @@ -549,7 +549,6 @@ void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, reslen = pqi_build_sas_smp_handler_reply(smp_buf, job, &error_info); out: bsg_job_done(job, rc, reslen); - pqi_ctrl_unbusy(ctrl_info); } struct sas_function_template pqi_sas_transport_functions = { .get_linkerrors = pqi_sas_get_linkerrors, diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index e2e5356a997d..43f7624508a9 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -2846,7 +2846,6 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon case MTNOP: DEBC_printk(STp, "No op on tape.\n"); return 0; /* Should do something ? */ - break; case MTRETEN: cmd[0] = START_STOP; if (STp->immediate) { diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index d4f10c0d813c..40473e4f850f 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -685,6 +685,7 @@ stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) done(cmd); return 0; } + break; default: break; } diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index a9fe092a4906..255a2d48d421 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -4596,7 +4596,6 @@ static void sym_int_sir(struct sym_hcb *np) scr_to_cpu(np->lastmsg), np->msgout[0]); } goto out_clrack; - break; default: goto out_reject; } diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index dcdb4eb1f90b..3f6dfed4fe84 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -99,7 +99,7 @@ config SCSI_UFS_DWC_TC_PLATFORM config SCSI_UFS_QCOM tristate "QCOM specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM - select QCOM_SCM + select QCOM_SCM if SCSI_UFS_CRYPTO select RESET_CONTROLLER help This selects the QCOM specific additions to UFSHCD platform driver. diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c index da065a259f6e..149391faa19c 100644 --- a/drivers/scsi/ufs/cdns-pltfrm.c +++ b/drivers/scsi/ufs/cdns-pltfrm.c @@ -221,8 +221,7 @@ static int cdns_ufs_init(struct ufs_hba *hba) return -ENOMEM; ufshcd_set_variant(hba, host); - if (hba->vops && hba->vops->phy_initialization) - status = hba->vops->phy_initialization(hba); + status = ufshcd_vops_phy_initialization(hba); return status; } diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c index 5e6b95dbb578..a8770ff14588 100644 --- a/drivers/scsi/ufs/ufs-exynos.c +++ b/drivers/scsi/ufs/ufs-exynos.c @@ -617,20 +617,7 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, goto out; } - - ufs_exynos_cap.tx_lanes = UFS_EXYNOS_LIMIT_NUM_LANES_TX; - ufs_exynos_cap.rx_lanes = UFS_EXYNOS_LIMIT_NUM_LANES_RX; - ufs_exynos_cap.hs_rx_gear = UFS_EXYNOS_LIMIT_HSGEAR_RX; - ufs_exynos_cap.hs_tx_gear = UFS_EXYNOS_LIMIT_HSGEAR_TX; - ufs_exynos_cap.pwm_rx_gear = UFS_EXYNOS_LIMIT_PWMGEAR_RX; - ufs_exynos_cap.pwm_tx_gear = UFS_EXYNOS_LIMIT_PWMGEAR_TX; - ufs_exynos_cap.rx_pwr_pwm = UFS_EXYNOS_LIMIT_RX_PWR_PWM; - ufs_exynos_cap.tx_pwr_pwm = UFS_EXYNOS_LIMIT_TX_PWR_PWM; - ufs_exynos_cap.rx_pwr_hs = UFS_EXYNOS_LIMIT_RX_PWR_HS; - ufs_exynos_cap.tx_pwr_hs = UFS_EXYNOS_LIMIT_TX_PWR_HS; - ufs_exynos_cap.hs_rate = UFS_EXYNOS_LIMIT_HS_RATE; - ufs_exynos_cap.desired_working_mode = - UFS_EXYNOS_LIMIT_DESIRED_MODE; + ufshcd_init_pwr_dev_param(&ufs_exynos_cap); ret = ufshcd_get_pwr_dev_param(&ufs_exynos_cap, dev_max_params, dev_req_params); diff --git a/drivers/scsi/ufs/ufs-exynos.h b/drivers/scsi/ufs/ufs-exynos.h index 76d6e39efb2f..06ee565f7eb0 100644 --- a/drivers/scsi/ufs/ufs-exynos.h +++ b/drivers/scsi/ufs/ufs-exynos.h @@ -90,19 +90,6 @@ struct exynos_ufs; #define SLOW 1 #define FAST 2 -#define UFS_EXYNOS_LIMIT_NUM_LANES_RX 2 -#define UFS_EXYNOS_LIMIT_NUM_LANES_TX 2 -#define UFS_EXYNOS_LIMIT_HSGEAR_RX UFS_HS_G3 -#define UFS_EXYNOS_LIMIT_HSGEAR_TX UFS_HS_G3 -#define UFS_EXYNOS_LIMIT_PWMGEAR_RX UFS_PWM_G4 -#define UFS_EXYNOS_LIMIT_PWMGEAR_TX UFS_PWM_G4 -#define UFS_EXYNOS_LIMIT_RX_PWR_PWM SLOW_MODE -#define UFS_EXYNOS_LIMIT_TX_PWR_PWM SLOW_MODE -#define UFS_EXYNOS_LIMIT_RX_PWR_HS FAST_MODE -#define UFS_EXYNOS_LIMIT_TX_PWR_HS FAST_MODE -#define UFS_EXYNOS_LIMIT_HS_RATE PA_HS_MODE_B -#define UFS_EXYNOS_LIMIT_DESIRED_MODE FAST - #define RX_ADV_FINE_GRAN_SUP_EN 0x1 #define RX_ADV_FINE_GRAN_STEP_VAL 0x3 #define RX_ADV_MIN_ACTV_TIME_CAP 0x9 diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c index 074a6a055a4c..0aa58131e791 100644 --- a/drivers/scsi/ufs/ufs-hisi.c +++ b/drivers/scsi/ufs/ufs-hisi.c @@ -293,18 +293,7 @@ static int ufs_hisi_link_startup_notify(struct ufs_hba *hba, static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param) { - hisi_param->rx_lanes = UFS_HISI_LIMIT_NUM_LANES_RX; - hisi_param->tx_lanes = UFS_HISI_LIMIT_NUM_LANES_TX; - hisi_param->hs_rx_gear = UFS_HISI_LIMIT_HSGEAR_RX; - hisi_param->hs_tx_gear = UFS_HISI_LIMIT_HSGEAR_TX; - hisi_param->pwm_rx_gear = UFS_HISI_LIMIT_PWMGEAR_RX; - hisi_param->pwm_tx_gear = UFS_HISI_LIMIT_PWMGEAR_TX; - hisi_param->rx_pwr_pwm = UFS_HISI_LIMIT_RX_PWR_PWM; - hisi_param->tx_pwr_pwm = UFS_HISI_LIMIT_TX_PWR_PWM; - hisi_param->rx_pwr_hs = UFS_HISI_LIMIT_RX_PWR_HS; - hisi_param->tx_pwr_hs = UFS_HISI_LIMIT_TX_PWR_HS; - hisi_param->hs_rate = UFS_HISI_LIMIT_HS_RATE; - hisi_param->desired_working_mode = UFS_HISI_LIMIT_DESIRED_MODE; + ufshcd_init_pwr_dev_param(hisi_param); } static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba) diff --git a/drivers/scsi/ufs/ufs-hisi.h b/drivers/scsi/ufs/ufs-hisi.h index 3231d3d81c98..5a90c0f4e90c 100644 --- a/drivers/scsi/ufs/ufs-hisi.h +++ b/drivers/scsi/ufs/ufs-hisi.h @@ -76,19 +76,6 @@ enum { #define SLOW 1 #define FAST 2 -#define UFS_HISI_LIMIT_NUM_LANES_RX 2 -#define UFS_HISI_LIMIT_NUM_LANES_TX 2 -#define UFS_HISI_LIMIT_HSGEAR_RX UFS_HS_G3 -#define UFS_HISI_LIMIT_HSGEAR_TX UFS_HS_G3 -#define UFS_HISI_LIMIT_PWMGEAR_RX UFS_PWM_G4 -#define UFS_HISI_LIMIT_PWMGEAR_TX UFS_PWM_G4 -#define UFS_HISI_LIMIT_RX_PWR_PWM SLOW_MODE -#define UFS_HISI_LIMIT_TX_PWR_PWM SLOW_MODE -#define UFS_HISI_LIMIT_RX_PWR_HS FAST_MODE -#define UFS_HISI_LIMIT_TX_PWR_HS FAST_MODE -#define UFS_HISI_LIMIT_HS_RATE PA_HS_MODE_B -#define UFS_HISI_LIMIT_DESIRED_MODE FAST - #define UFS_HISI_CAP_RESERVED BIT(0) #define UFS_HISI_CAP_PHY10nm BIT(1) diff --git a/drivers/scsi/ufs/ufs-mediatek-trace.h b/drivers/scsi/ufs/ufs-mediatek-trace.h new file mode 100644 index 000000000000..fd6f84c1b4e2 --- /dev/null +++ b/drivers/scsi/ufs/ufs-mediatek-trace.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 MediaTek Inc. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM ufs_mtk + +#if !defined(_TRACE_EVENT_UFS_MEDIATEK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_EVENT_UFS_MEDIATEK_H + +#include <linux/tracepoint.h> + +TRACE_EVENT(ufs_mtk_event, + TP_PROTO(unsigned int type, unsigned int data), + TP_ARGS(type, data), + + TP_STRUCT__entry( + __field(unsigned int, type) + __field(unsigned int, data) + ), + + TP_fast_assign( + __entry->type = type; + __entry->data = data; + ), + + TP_printk("ufs:event=%u data=%u", + __entry->type, __entry->data) + ); +#endif + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE ufs-mediatek-trace +#include <trace/define_trace.h> diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c index 8df73bc2f8cb..3522458db3bb 100644 --- a/drivers/scsi/ufs/ufs-mediatek.c +++ b/drivers/scsi/ufs/ufs-mediatek.c @@ -24,10 +24,16 @@ #include "unipro.h" #include "ufs-mediatek.h" +#define CREATE_TRACE_POINTS +#include "ufs-mediatek-trace.h" + #define ufs_mtk_smc(cmd, val, res) \ arm_smccc_smc(MTK_SIP_UFS_CONTROL, \ cmd, val, 0, 0, 0, 0, 0, &(res)) +#define ufs_mtk_va09_pwr_ctrl(res, on) \ + ufs_mtk_smc(UFS_MTK_SIP_VA09_PWR_CTRL, on, res) + #define ufs_mtk_crypto_ctrl(res, enable) \ ufs_mtk_smc(UFS_MTK_SIP_CRYPTO_CTRL, enable, res) @@ -45,18 +51,8 @@ static struct ufs_dev_fix ufs_mtk_dev_fixups[] = { END_FIX }; -static const struct ufs_mtk_host_cfg ufs_mtk_mt8192_cfg = { - .caps = UFS_MTK_CAP_BOOST_CRYPT_ENGINE, -}; - static const struct of_device_id ufs_mtk_of_match[] = { - { - .compatible = "mediatek,mt8183-ufshci", - }, - { - .compatible = "mediatek,mt8192-ufshci", - .data = &ufs_mtk_mt8192_cfg - }, + { .compatible = "mediatek,mt8183-ufshci" }, {}, }; @@ -64,7 +60,14 @@ static bool ufs_mtk_is_boost_crypt_enabled(struct ufs_hba *hba) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); - return (host->caps & UFS_MTK_CAP_BOOST_CRYPT_ENGINE); + return !!(host->caps & UFS_MTK_CAP_BOOST_CRYPT_ENGINE); +} + +static bool ufs_mtk_is_va09_supported(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + return !!(host->caps & UFS_MTK_CAP_VA09_PWR_CTRL); } static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable) @@ -158,6 +161,7 @@ static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); + unsigned long flags; if (status == PRE_CHANGE) { if (host->unipro_lpm) { @@ -169,6 +173,17 @@ static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba, if (hba->caps & UFSHCD_CAP_CRYPTO) ufs_mtk_crypto_enable(hba); + + if (host->caps & UFS_MTK_CAP_DISABLE_AH8) { + spin_lock_irqsave(hba->host->host_lock, flags); + ufshcd_writel(hba, 0, + REG_AUTO_HIBERNATE_IDLE_TIMER); + spin_unlock_irqrestore(hba->host->host_lock, + flags); + + hba->capabilities &= ~MASK_AUTO_HIBERN8_SUPPORT; + hba->ahit = 0; + } } return 0; @@ -300,21 +315,46 @@ static int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state, return -ETIMEDOUT; } -static void ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on) +static int ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); struct phy *mphy = host->mphy; + struct arm_smccc_res res; + int ret = 0; - if (!mphy) - return; + if (!mphy || !(on ^ host->mphy_powered_on)) + return 0; - if (on && !host->mphy_powered_on) + if (on) { + if (ufs_mtk_is_va09_supported(hba)) { + ret = regulator_enable(host->reg_va09); + if (ret < 0) + goto out; + /* wait 200 us to stablize VA09 */ + usleep_range(200, 210); + ufs_mtk_va09_pwr_ctrl(res, 1); + } phy_power_on(mphy); - else if (!on && host->mphy_powered_on) + } else { phy_power_off(mphy); - else - return; - host->mphy_powered_on = on; + if (ufs_mtk_is_va09_supported(hba)) { + ufs_mtk_va09_pwr_ctrl(res, 0); + ret = regulator_disable(host->reg_va09); + if (ret < 0) + goto out; + } + } +out: + if (ret) { + dev_info(hba->dev, + "failed to %s va09: %d\n", + on ? "enable" : "disable", + ret); + } else { + host->mphy_powered_on = on; + } + + return ret; } static int ufs_mtk_get_host_clk(struct device *dev, const char *name, @@ -402,7 +442,7 @@ static int ufs_mtk_init_host_clk(struct ufs_hba *hba, const char *name, return ret; } -static void ufs_mtk_init_host_caps(struct ufs_hba *hba) +static void ufs_mtk_init_boost_crypt(struct ufs_hba *hba) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); struct ufs_mtk_crypt_cfg *cfg; @@ -410,11 +450,6 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba) struct regulator *reg; u32 volt; - host->caps = host->cfg->caps; - - if (!ufs_mtk_is_boost_crypt_enabled(hba)) - return; - host->crypt = devm_kzalloc(dev, sizeof(*(host->crypt)), GFP_KERNEL); if (!host->crypt) @@ -448,11 +483,51 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba) cfg->reg_vcore = reg; cfg->vcore_volt = volt; - dev_info(dev, "caps: boost-crypt"); - return; + host->caps |= UFS_MTK_CAP_BOOST_CRYPT_ENGINE; disable_caps: - host->caps &= ~UFS_MTK_CAP_BOOST_CRYPT_ENGINE; + return; +} + +static void ufs_mtk_init_va09_pwr_ctrl(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + host->reg_va09 = regulator_get(hba->dev, "va09"); + if (!host->reg_va09) + dev_info(hba->dev, "failed to get va09"); + else + host->caps |= UFS_MTK_CAP_VA09_PWR_CTRL; +} + +static void ufs_mtk_init_host_caps(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + struct device_node *np = hba->dev->of_node; + + if (of_property_read_bool(np, "mediatek,ufs-boost-crypt")) + ufs_mtk_init_boost_crypt(hba); + + if (of_property_read_bool(np, "mediatek,ufs-support-va09")) + ufs_mtk_init_va09_pwr_ctrl(hba); + + if (of_property_read_bool(np, "mediatek,ufs-disable-ah8")) + host->caps |= UFS_MTK_CAP_DISABLE_AH8; + + dev_info(hba->dev, "caps: 0x%x", host->caps); +} + +static void ufs_mtk_scale_perf(struct ufs_hba *hba, bool up) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + ufs_mtk_boost_crypt(hba, up); + ufs_mtk_setup_ref_clk(hba, up); + + if (up) + phy_power_on(host->mphy); + else + phy_power_off(host->mphy); } /** @@ -467,8 +542,8 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); - int ret = 0; bool clk_pwr_off = false; + int ret = 0; /* * In case ufs_mtk_init() is not yet done, simply ignore. @@ -496,20 +571,33 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, clk_pwr_off = true; } - if (clk_pwr_off) { - ufs_mtk_boost_crypt(hba, on); - ufs_mtk_setup_ref_clk(hba, on); - ufs_mtk_mphy_power_on(hba, on); - } + if (clk_pwr_off) + ufs_mtk_scale_perf(hba, false); } else if (on && status == POST_CHANGE) { - ufs_mtk_mphy_power_on(hba, on); - ufs_mtk_setup_ref_clk(hba, on); - ufs_mtk_boost_crypt(hba, on); + ufs_mtk_scale_perf(hba, true); } return ret; } +static void ufs_mtk_get_controller_version(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + int ret, ver = 0; + + if (host->hw_ver.major) + return; + + /* Set default (minimum) version anyway */ + host->hw_ver.major = 2; + + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_LOCALVERINFO), &ver); + if (!ret) { + if (ver >= UFS_UNIPRO_VER_1_8) + host->hw_ver.major = 3; + } +} + /** * ufs_mtk_init - find other essential mmio bases * @hba: host controller instance @@ -537,17 +625,14 @@ static int ufs_mtk_init(struct ufs_hba *hba) host->hba = hba; ufshcd_set_variant(hba, host); - /* Get host capability and platform data */ id = of_match_device(ufs_mtk_of_match, dev); if (!id) { err = -EINVAL; goto out; } - if (id->data) { - host->cfg = (struct ufs_mtk_host_cfg *)id->data; - ufs_mtk_init_host_caps(hba); - } + /* Initialize host capability */ + ufs_mtk_init_host_caps(hba); err = ufs_mtk_bind_mphy(hba); if (err) @@ -568,6 +653,9 @@ static int ufs_mtk_init(struct ufs_hba *hba) hba->caps |= UFSHCD_CAP_WB_EN; hba->vps->wb_flush_threshold = UFS_WB_BUF_REMAIN_PERCENT(80); + if (host->caps & UFS_MTK_CAP_DISABLE_AH8) + hba->caps |= UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; + /* * ufshcd_vops_init() is invoked after * ufshcd_setup_clock(true) in ufshcd_hba_init() thus @@ -575,6 +663,7 @@ static int ufs_mtk_init(struct ufs_hba *hba) * * Enable phy clocks specifically here. */ + ufs_mtk_mphy_power_on(hba, true); ufs_mtk_setup_clocks(hba, true, POST_CHANGE); goto out; @@ -589,22 +678,13 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) { + struct ufs_mtk_host *host = ufshcd_get_variant(hba); struct ufs_dev_params host_cap; int ret; - host_cap.tx_lanes = UFS_MTK_LIMIT_NUM_LANES_TX; - host_cap.rx_lanes = UFS_MTK_LIMIT_NUM_LANES_RX; - host_cap.hs_rx_gear = UFS_MTK_LIMIT_HSGEAR_RX; - host_cap.hs_tx_gear = UFS_MTK_LIMIT_HSGEAR_TX; - host_cap.pwm_rx_gear = UFS_MTK_LIMIT_PWMGEAR_RX; - host_cap.pwm_tx_gear = UFS_MTK_LIMIT_PWMGEAR_TX; - host_cap.rx_pwr_pwm = UFS_MTK_LIMIT_RX_PWR_PWM; - host_cap.tx_pwr_pwm = UFS_MTK_LIMIT_TX_PWR_PWM; - host_cap.rx_pwr_hs = UFS_MTK_LIMIT_RX_PWR_HS; - host_cap.tx_pwr_hs = UFS_MTK_LIMIT_TX_PWR_HS; - host_cap.hs_rate = UFS_MTK_LIMIT_HS_RATE; - host_cap.desired_working_mode = - UFS_MTK_LIMIT_DESIRED_MODE; + ufshcd_init_pwr_dev_param(&host_cap); + host_cap.hs_rx_gear = UFS_HS_G4; + host_cap.hs_tx_gear = UFS_HS_G4; ret = ufshcd_get_pwr_dev_param(&host_cap, dev_max_params, @@ -614,6 +694,12 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, __func__); } + if (host->hw_ver.major >= 3) { + ret = ufshcd_dme_configure_adapt(hba, + dev_req_params->gear_tx, + PA_INITIAL_ADAPT); + } + return ret; } @@ -639,14 +725,14 @@ static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba, return ret; } -static int ufs_mtk_unipro_set_pm(struct ufs_hba *hba, bool lpm) +static int ufs_mtk_unipro_set_lpm(struct ufs_hba *hba, bool lpm) { int ret; struct ufs_mtk_host *host = ufshcd_get_variant(hba); ret = ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VS_UNIPROPOWERDOWNCONTROL, 0), - lpm); + lpm ? 1 : 0); if (!ret || !lpm) { /* * Forcibly set as non-LPM mode if UIC commands is failed @@ -664,7 +750,9 @@ static int ufs_mtk_pre_link(struct ufs_hba *hba) int ret; u32 tmp; - ret = ufs_mtk_unipro_set_pm(hba, false); + ufs_mtk_get_controller_version(hba); + + ret = ufs_mtk_unipro_set_lpm(hba, false); if (ret) return ret; @@ -743,7 +831,7 @@ static int ufs_mtk_link_startup_notify(struct ufs_hba *hba, return ret; } -static void ufs_mtk_device_reset(struct ufs_hba *hba) +static int ufs_mtk_device_reset(struct ufs_hba *hba) { struct arm_smccc_res res; @@ -764,6 +852,8 @@ static void ufs_mtk_device_reset(struct ufs_hba *hba) usleep_range(10000, 15000); dev_info(hba->dev, "device reset done\n"); + + return 0; } static int ufs_mtk_link_set_hpm(struct ufs_hba *hba) @@ -774,7 +864,7 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba) if (err) return err; - err = ufs_mtk_unipro_set_pm(hba, false); + err = ufs_mtk_unipro_set_lpm(hba, false); if (err) return err; @@ -795,10 +885,10 @@ static int ufs_mtk_link_set_lpm(struct ufs_hba *hba) { int err; - err = ufs_mtk_unipro_set_pm(hba, true); + err = ufs_mtk_unipro_set_lpm(hba, true); if (err) { /* Resume UniPro state for following error recovery */ - ufs_mtk_unipro_set_pm(hba, false); + ufs_mtk_unipro_set_lpm(hba, false); return err; } @@ -824,40 +914,52 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ufshcd_is_link_hibern8(hba)) { err = ufs_mtk_link_set_lpm(hba); - if (err) { - /* - * Set link as off state enforcedly to trigger - * ufshcd_host_reset_and_restore() in ufshcd_suspend() - * for completed host reset. - */ - ufshcd_set_link_off(hba); - return -EAGAIN; - } + if (err) + goto fail; + } + + if (!ufshcd_is_link_active(hba)) { /* * Make sure no error will be returned to prevent * ufshcd_suspend() re-enabling regulators while vreg is still * in low-power mode. */ ufs_mtk_vreg_set_lpm(hba, true); + err = ufs_mtk_mphy_power_on(hba, false); + if (err) + goto fail; } return 0; +fail: + /* + * Set link as off state enforcedly to trigger + * ufshcd_host_reset_and_restore() in ufshcd_suspend() + * for completed host reset. + */ + ufshcd_set_link_off(hba); + return -EAGAIN; } static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) { int err; + err = ufs_mtk_mphy_power_on(hba, true); + if (err) + goto fail; + + ufs_mtk_vreg_set_lpm(hba, false); + if (ufshcd_is_link_hibern8(hba)) { - ufs_mtk_vreg_set_lpm(hba, false); err = ufs_mtk_link_set_hpm(hba); - if (err) { - err = ufshcd_link_recovery(hba); - return err; - } + if (err) + goto fail; } return 0; +fail: + return ufshcd_link_recovery(hba); } static void ufs_mtk_dbg_register_dump(struct ufs_hba *hba) @@ -903,6 +1005,14 @@ static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba) ufshcd_fixup_dev_quirks(hba, ufs_mtk_dev_fixups); } +static void ufs_mtk_event_notify(struct ufs_hba *hba, + enum ufs_event_type evt, void *data) +{ + unsigned int val = *(u32 *)data; + + trace_ufs_mtk_event(evt, val); +} + /* * struct ufs_hba_mtk_vops - UFS MTK specific variant operations * @@ -922,6 +1032,7 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = { .resume = ufs_mtk_resume, .dbg_register_dump = ufs_mtk_dbg_register_dump, .device_reset = ufs_mtk_device_reset, + .event_notify = ufs_mtk_event_notify, }; /** diff --git a/drivers/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h index 2b6a1312c9bc..93d35097dfb0 100644 --- a/drivers/scsi/ufs/ufs-mediatek.h +++ b/drivers/scsi/ufs/ufs-mediatek.h @@ -31,22 +31,6 @@ #define REFCLK_REQ_TIMEOUT_US 3000 /* - * Vendor specific pre-defined parameters - */ -#define UFS_MTK_LIMIT_NUM_LANES_RX 2 -#define UFS_MTK_LIMIT_NUM_LANES_TX 2 -#define UFS_MTK_LIMIT_HSGEAR_RX UFS_HS_G3 -#define UFS_MTK_LIMIT_HSGEAR_TX UFS_HS_G3 -#define UFS_MTK_LIMIT_PWMGEAR_RX UFS_PWM_G4 -#define UFS_MTK_LIMIT_PWMGEAR_TX UFS_PWM_G4 -#define UFS_MTK_LIMIT_RX_PWR_PWM SLOW_MODE -#define UFS_MTK_LIMIT_TX_PWR_PWM SLOW_MODE -#define UFS_MTK_LIMIT_RX_PWR_HS FAST_MODE -#define UFS_MTK_LIMIT_TX_PWR_HS FAST_MODE -#define UFS_MTK_LIMIT_HS_RATE PA_HS_MODE_B -#define UFS_MTK_LIMIT_DESIRED_MODE UFS_HS_MODE - -/* * Other attributes */ #define VS_DEBUGCLOCKENABLE 0xD0A1 @@ -69,6 +53,7 @@ enum { * SiP commands */ #define MTK_SIP_UFS_CONTROL MTK_SIP_SMC_CMD(0x276) +#define UFS_MTK_SIP_VA09_PWR_CTRL BIT(0) #define UFS_MTK_SIP_DEVICE_RESET BIT(1) #define UFS_MTK_SIP_CRYPTO_CTRL BIT(2) #define UFS_MTK_SIP_REF_CLK_NOTIFICATION BIT(3) @@ -94,6 +79,8 @@ enum { */ enum ufs_mtk_host_caps { UFS_MTK_CAP_BOOST_CRYPT_ENGINE = 1 << 0, + UFS_MTK_CAP_VA09_PWR_CTRL = 1 << 1, + UFS_MTK_CAP_DISABLE_AH8 = 1 << 2, }; struct ufs_mtk_crypt_cfg { @@ -104,19 +91,22 @@ struct ufs_mtk_crypt_cfg { int vcore_volt; }; -struct ufs_mtk_host_cfg { - enum ufs_mtk_host_caps caps; +struct ufs_mtk_hw_ver { + u8 step; + u8 minor; + u8 major; }; struct ufs_mtk_host { - struct ufs_hba *hba; struct phy *mphy; - struct ufs_mtk_host_cfg *cfg; - struct ufs_mtk_crypt_cfg *crypt; - enum ufs_mtk_host_caps caps; + struct regulator *reg_va09; struct reset_control *hci_reset; struct reset_control *unipro_reset; struct reset_control *crypto_reset; + struct ufs_hba *hba; + struct ufs_mtk_crypt_cfg *crypt; + struct ufs_mtk_hw_ver hw_ver; + enum ufs_mtk_host_caps caps; bool mphy_powered_on; bool unipro_lpm; bool ref_clk_enabled; diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index f9d6ef356540..2206b1e4b774 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -691,19 +691,8 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufs_qcom_cap.tx_lanes = UFS_QCOM_LIMIT_NUM_LANES_TX; - ufs_qcom_cap.rx_lanes = UFS_QCOM_LIMIT_NUM_LANES_RX; - ufs_qcom_cap.hs_rx_gear = UFS_QCOM_LIMIT_HSGEAR_RX; - ufs_qcom_cap.hs_tx_gear = UFS_QCOM_LIMIT_HSGEAR_TX; - ufs_qcom_cap.pwm_rx_gear = UFS_QCOM_LIMIT_PWMGEAR_RX; - ufs_qcom_cap.pwm_tx_gear = UFS_QCOM_LIMIT_PWMGEAR_TX; - ufs_qcom_cap.rx_pwr_pwm = UFS_QCOM_LIMIT_RX_PWR_PWM; - ufs_qcom_cap.tx_pwr_pwm = UFS_QCOM_LIMIT_TX_PWR_PWM; - ufs_qcom_cap.rx_pwr_hs = UFS_QCOM_LIMIT_RX_PWR_HS; - ufs_qcom_cap.tx_pwr_hs = UFS_QCOM_LIMIT_TX_PWR_HS; + ufshcd_init_pwr_dev_param(&ufs_qcom_cap); ufs_qcom_cap.hs_rate = UFS_QCOM_LIMIT_HS_RATE; - ufs_qcom_cap.desired_working_mode = - UFS_QCOM_LIMIT_DESIRED_MODE; if (host->hw_ver.major == 0x1) { /* @@ -734,17 +723,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, ufs_qcom_dev_ref_clk_ctrl(host, true); if (host->hw_ver.major >= 0x4) { - if (dev_req_params->gear_tx == UFS_HS_G4) { - /* INITIAL ADAPT */ - ufshcd_dme_set(hba, - UIC_ARG_MIB(PA_TXHSADAPTTYPE), - PA_INITIAL_ADAPT); - } else { - /* NO ADAPT */ - ufshcd_dme_set(hba, - UIC_ARG_MIB(PA_TXHSADAPTTYPE), - PA_NO_ADAPT); - } + ufshcd_dme_configure_adapt(hba, + dev_req_params->gear_tx, + PA_INITIAL_ADAPT); } break; case POST_CHANGE: @@ -863,6 +844,7 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba) hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; hba->caps |= UFSHCD_CAP_WB_EN; hba->caps |= UFSHCD_CAP_CRYPTO; + hba->caps |= UFSHCD_CAP_AGGR_POWER_COLLAPSE; if (host->hw_ver.major >= 0x2) { host->caps = UFS_QCOM_CAP_QUNIPRO | @@ -977,6 +959,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) struct platform_device *pdev = to_platform_device(dev); struct ufs_qcom_host *host; struct resource *res; + struct ufs_clk_info *clki; if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev))) return -ENODEV; @@ -1075,6 +1058,11 @@ static int ufs_qcom_init(struct ufs_hba *hba) } } + list_for_each_entry(clki, &hba->clk_list_head, list) { + if (!strcmp(clki->name, "core_clk_unipro")) + clki->keep_link_active = true; + } + err = ufs_qcom_init_lane_clks(host); if (err) goto out_variant_clear; @@ -1421,13 +1409,13 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) * * Toggles the (optional) reset line to reset the attached device. */ -static void ufs_qcom_device_reset(struct ufs_hba *hba) +static int ufs_qcom_device_reset(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); /* reset gpio is optional */ if (!host->device_reset) - return; + return -EOPNOTSUPP; /* * The UFS device shall detect reset pulses of 1us, sleep for 10us to @@ -1438,6 +1426,8 @@ static void ufs_qcom_device_reset(struct ufs_hba *hba) gpiod_set_value_cansleep(host->device_reset, 0); usleep_range(10, 15); + + return 0; } #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 3f4922743b3e..8208e3a3ef59 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -27,18 +27,7 @@ #define SLOW 1 #define FAST 2 -#define UFS_QCOM_LIMIT_NUM_LANES_RX 2 -#define UFS_QCOM_LIMIT_NUM_LANES_TX 2 -#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G3 -#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G3 -#define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4 -#define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4 -#define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE -#define UFS_QCOM_LIMIT_TX_PWR_PWM SLOW_MODE -#define UFS_QCOM_LIMIT_RX_PWR_HS FAST_MODE -#define UFS_QCOM_LIMIT_TX_PWR_HS FAST_MODE #define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B -#define UFS_QCOM_LIMIT_DESIRED_MODE FAST /* QCOM UFS host controller vendor specific registers */ enum { diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c index bdcd27faa054..08e72b7eef6a 100644 --- a/drivers/scsi/ufs/ufs-sysfs.c +++ b/drivers/scsi/ufs/ufs-sysfs.c @@ -28,6 +28,7 @@ static const char *ufschd_ufs_dev_pwr_mode_to_string( case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; case UFS_SLEEP_PWR_MODE: return "SLEEP"; case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; + case UFS_DEEPSLEEP_PWR_MODE: return "DEEPSLEEP"; default: return "UNKNOWN"; } } @@ -38,6 +39,7 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, bool rpm) { struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_dev_info *dev_info = &hba->dev_info; unsigned long flags, value; if (kstrtoul(buf, 0, &value)) @@ -46,6 +48,11 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, if (value >= UFS_PM_LVL_MAX) return -EINVAL; + if (ufs_pm_lvl_states[value].dev_state == UFS_DEEPSLEEP_PWR_MODE && + (!(hba->caps & UFSHCD_CAP_DEEPSLEEP) || + !(dev_info->wspecversion >= 0x310))) + return -EINVAL; + spin_lock_irqsave(hba->host->host_lock, flags); if (rpm) hba->rpm_lvl = value; diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index f8ab16f30fdc..d593edb48767 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -442,6 +442,7 @@ enum ufs_dev_pwr_mode { UFS_ACTIVE_PWR_MODE = 1, UFS_SLEEP_PWR_MODE = 2, UFS_POWERDOWN_PWR_MODE = 3, + UFS_DEEPSLEEP_PWR_MODE = 4, }; #define UFS_WB_BUF_REMAIN_PERCENT(val) ((val) / 10) diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c index 6a901da2d15a..5bb9d3a88795 100644 --- a/drivers/scsi/ufs/ufshcd-dwc.c +++ b/drivers/scsi/ufs/ufshcd-dwc.c @@ -120,13 +120,10 @@ int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba, if (status == PRE_CHANGE) { ufshcd_dwc_program_clk_div(hba, DWC_UFS_REG_HCLKDIV_DIV_125); - if (hba->vops->phy_initialization) { - err = hba->vops->phy_initialization(hba); - if (err) { - dev_err(hba->dev, "Phy setup failed (%d)\n", - err); - goto out; - } + err = ufshcd_vops_phy_initialization(hba); + if (err) { + dev_err(hba->dev, "Phy setup failed (%d)\n", err); + goto out; } } else { /* POST_CHANGE */ err = ufshcd_dwc_link_is_up(hba); diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 3db0af66c71c..1a69949a4ea1 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -92,6 +92,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba) clki->min_freq = clkfreq[i]; clki->max_freq = clkfreq[i+1]; clki->name = kstrdup(name, GFP_KERNEL); + if (!strcmp(name, "ref_clk")) + clki->keep_link_active = true; dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz", clki->min_freq, clki->max_freq, clki->name); list_add_tail(&clki->list, &hba->clk_list_head); @@ -132,25 +134,6 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name, dev_info(dev, "%s: unable to find %s\n", __func__, prop_name); vreg->max_uA = 0; } - - if (!strcmp(name, "vcc")) { - if (of_property_read_bool(np, "vcc-supply-1p8")) { - vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV; - vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV; - } else { - vreg->min_uV = UFS_VREG_VCC_MIN_UV; - vreg->max_uV = UFS_VREG_VCC_MAX_UV; - } - } else if (!strcmp(name, "vccq")) { - vreg->min_uV = UFS_VREG_VCCQ_MIN_UV; - vreg->max_uV = UFS_VREG_VCCQ_MAX_UV; - } else if (!strcmp(name, "vccq2")) { - vreg->min_uV = UFS_VREG_VCCQ2_MIN_UV; - vreg->max_uV = UFS_VREG_VCCQ2_MAX_UV; - } - - goto out; - out: if (!ret) *out_vreg = vreg; @@ -354,6 +337,23 @@ int ufshcd_get_pwr_dev_param(struct ufs_dev_params *pltfrm_param, } EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param); +void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param) +{ + dev_param->tx_lanes = 2; + dev_param->rx_lanes = 2; + dev_param->hs_rx_gear = UFS_HS_G3; + dev_param->hs_tx_gear = UFS_HS_G3; + dev_param->pwm_rx_gear = UFS_PWM_G4; + dev_param->pwm_tx_gear = UFS_PWM_G4; + dev_param->rx_pwr_pwm = SLOW_MODE; + dev_param->tx_pwr_pwm = SLOW_MODE; + dev_param->rx_pwr_hs = FAST_MODE; + dev_param->tx_pwr_hs = FAST_MODE; + dev_param->hs_rate = PA_HS_MODE_B; + dev_param->desired_working_mode = UFS_HS_MODE; +} +EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param); + /** * ufshcd_pltfrm_init - probe routine of the driver * @pdev: pointer to Platform device handle diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h index b79cdf9129a0..772a8e848098 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.h +++ b/drivers/scsi/ufs/ufshcd-pltfrm.h @@ -28,6 +28,7 @@ struct ufs_dev_params { int ufshcd_get_pwr_dev_param(struct ufs_dev_params *dev_param, struct ufs_pa_layer_attr *dev_max, struct ufs_pa_layer_attr *agreed_pwr); +void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param); int ufshcd_pltfrm_init(struct platform_device *pdev, const struct ufs_hba_variant_ops *vops); void ufshcd_pltfrm_shutdown(struct platform_device *pdev); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0c148fcd24de..9902b7e3aa4a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -163,6 +163,11 @@ struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE}, + /* + * For DeepSleep, the link is first put in hibern8 and then off. + * Leaving the link in hibern8 is not supported. + */ + {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE}, }; static inline enum ufs_dev_pwr_mode @@ -221,8 +226,6 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd); static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); static void ufshcd_hba_exit(struct ufs_hba *hba); static int ufshcd_probe_hba(struct ufs_hba *hba, bool async); -static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, - bool skip_ref_clk); static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); @@ -245,6 +248,8 @@ static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba); static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable); static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool set); static inline void ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable); +static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba); +static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba); static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag) { @@ -348,7 +353,7 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, const char *str) { sector_t lba = -1; - u8 opcode = 0; + u8 opcode = 0, group_id = 0; u32 intr, doorbell; struct ufshcd_lrb *lrbp = &hba->lrb[tag]; struct scsi_cmnd *cmd = lrbp->cmd; @@ -374,13 +379,20 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, lba = cmd->request->bio->bi_iter.bi_sector; transfer_len = be32_to_cpu( lrbp->ucd_req_ptr->sc.exp_data_transfer_len); + if (opcode == WRITE_10) + group_id = lrbp->cmd->cmnd[6]; + } else if (opcode == UNMAP) { + if (cmd->request) { + lba = scsi_get_lba(cmd); + transfer_len = blk_rq_bytes(cmd->request); + } } } intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS); doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); trace_ufshcd_command(dev_name(hba->dev), str, tag, - doorbell, transfer_len, intr, lba, opcode); + doorbell, transfer_len, intr, lba, opcode, group_id); } static void ufshcd_print_clk_freqs(struct ufs_hba *hba) @@ -399,20 +411,25 @@ static void ufshcd_print_clk_freqs(struct ufs_hba *hba) } } -static void ufshcd_print_err_hist(struct ufs_hba *hba, - struct ufs_err_reg_hist *err_hist, - char *err_name) +static void ufshcd_print_evt(struct ufs_hba *hba, u32 id, + char *err_name) { int i; bool found = false; + struct ufs_event_hist *e; - for (i = 0; i < UFS_ERR_REG_HIST_LENGTH; i++) { - int p = (i + err_hist->pos) % UFS_ERR_REG_HIST_LENGTH; + if (id >= UFS_EVT_CNT) + return; - if (err_hist->tstamp[p] == 0) + e = &hba->ufs_stats.event[id]; + + for (i = 0; i < UFS_EVENT_HIST_LENGTH; i++) { + int p = (i + e->pos) % UFS_EVENT_HIST_LENGTH; + + if (e->tstamp[p] == 0) continue; dev_err(hba->dev, "%s[%d] = 0x%x at %lld us\n", err_name, p, - err_hist->reg[p], ktime_to_us(err_hist->tstamp[p])); + e->val[p], ktime_to_us(e->tstamp[p])); found = true; } @@ -420,26 +437,26 @@ static void ufshcd_print_err_hist(struct ufs_hba *hba, dev_err(hba->dev, "No record of %s\n", err_name); } -static void ufshcd_print_host_regs(struct ufs_hba *hba) +static void ufshcd_print_evt_hist(struct ufs_hba *hba) { ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: "); - ufshcd_print_err_hist(hba, &hba->ufs_stats.pa_err, "pa_err"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.dl_err, "dl_err"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.nl_err, "nl_err"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.tl_err, "tl_err"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.dme_err, "dme_err"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.auto_hibern8_err, - "auto_hibern8_err"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.fatal_err, "fatal_err"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.link_startup_err, - "link_startup_fail"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.resume_err, "resume_fail"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.suspend_err, - "suspend_fail"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.dev_reset, "dev_reset"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.host_reset, "host_reset"); - ufshcd_print_err_hist(hba, &hba->ufs_stats.task_abort, "task_abort"); + ufshcd_print_evt(hba, UFS_EVT_PA_ERR, "pa_err"); + ufshcd_print_evt(hba, UFS_EVT_DL_ERR, "dl_err"); + ufshcd_print_evt(hba, UFS_EVT_NL_ERR, "nl_err"); + ufshcd_print_evt(hba, UFS_EVT_TL_ERR, "tl_err"); + ufshcd_print_evt(hba, UFS_EVT_DME_ERR, "dme_err"); + ufshcd_print_evt(hba, UFS_EVT_AUTO_HIBERN8_ERR, + "auto_hibern8_err"); + ufshcd_print_evt(hba, UFS_EVT_FATAL_ERR, "fatal_err"); + ufshcd_print_evt(hba, UFS_EVT_LINK_STARTUP_FAIL, + "link_startup_fail"); + ufshcd_print_evt(hba, UFS_EVT_RESUME_ERR, "resume_fail"); + ufshcd_print_evt(hba, UFS_EVT_SUSPEND_ERR, + "suspend_fail"); + ufshcd_print_evt(hba, UFS_EVT_DEV_RESET, "dev_reset"); + ufshcd_print_evt(hba, UFS_EVT_HOST_RESET, "host_reset"); + ufshcd_print_evt(hba, UFS_EVT_ABORT, "task_abort"); ufshcd_vops_dbg_register_dump(hba); } @@ -1102,7 +1119,6 @@ out: */ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up) { - #define UFS_MIN_GEAR_TO_SCALE_DOWN UFS_HS_G1 int ret = 0; struct ufs_pa_layer_attr new_pwr_info; @@ -1113,16 +1129,16 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up) memcpy(&new_pwr_info, &hba->pwr_info, sizeof(struct ufs_pa_layer_attr)); - if (hba->pwr_info.gear_tx > UFS_MIN_GEAR_TO_SCALE_DOWN - || hba->pwr_info.gear_rx > UFS_MIN_GEAR_TO_SCALE_DOWN) { + if (hba->pwr_info.gear_tx > hba->clk_scaling.min_gear || + hba->pwr_info.gear_rx > hba->clk_scaling.min_gear) { /* save the current power mode */ memcpy(&hba->clk_scaling.saved_pwr_info.info, &hba->pwr_info, sizeof(struct ufs_pa_layer_attr)); /* scale down gear */ - new_pwr_info.gear_tx = UFS_MIN_GEAR_TO_SCALE_DOWN; - new_pwr_info.gear_rx = UFS_MIN_GEAR_TO_SCALE_DOWN; + new_pwr_info.gear_tx = hba->clk_scaling.min_gear; + new_pwr_info.gear_rx = hba->clk_scaling.min_gear; } } @@ -1555,6 +1571,7 @@ static void ufshcd_ungate_work(struct work_struct *work) } spin_unlock_irqrestore(hba->host->host_lock, flags); + ufshcd_hba_vreg_set_hpm(hba); ufshcd_setup_clocks(hba, true); ufshcd_enable_irq(hba); @@ -1714,12 +1731,10 @@ static void ufshcd_gate_work(struct work_struct *work) ufshcd_disable_irq(hba); - if (!ufshcd_is_link_active(hba)) - ufshcd_setup_clocks(hba, false); - else - /* If link is active, device ref_clk can't be switched off */ - __ufshcd_setup_clocks(hba, false, true); + ufshcd_setup_clocks(hba, false); + /* Put the host controller in low power mode if possible */ + ufshcd_hba_vreg_set_lpm(hba); /* * In case you are here to cancel this work the gating state * would be marked as REQ_CLKS_ON. In this case keep the state @@ -1751,8 +1766,9 @@ static void __ufshcd_release(struct ufs_hba *hba) if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL || - ufshcd_any_tag_in_use(hba) || hba->outstanding_tasks || - hba->active_uic_cmd || hba->uic_async_done) + hba->outstanding_tasks || + hba->active_uic_cmd || hba->uic_async_done || + hba->clk_gating.state == CLKS_OFF) return; hba->clk_gating.state = REQ_CLKS_OFF; @@ -1814,19 +1830,19 @@ static ssize_t ufshcd_clkgate_enable_store(struct device *dev, return -EINVAL; value = !!value; + + spin_lock_irqsave(hba->host->host_lock, flags); if (value == hba->clk_gating.is_enabled) goto out; - if (value) { - ufshcd_release(hba); - } else { - spin_lock_irqsave(hba->host->host_lock, flags); + if (value) + __ufshcd_release(hba); + else hba->clk_gating.active_reqs++; - spin_unlock_irqrestore(hba->host->host_lock, flags); - } hba->clk_gating.is_enabled = value; out: + spin_unlock_irqrestore(hba->host->host_lock, flags); return count; } @@ -1837,6 +1853,9 @@ static void ufshcd_init_clk_scaling(struct ufs_hba *hba) if (!ufshcd_is_clkscaling_supported(hba)) return; + if (!hba->clk_scaling.min_gear) + hba->clk_scaling.min_gear = UFS_HS_G1; + INIT_WORK(&hba->clk_scaling.suspend_work, ufshcd_clk_scaling_suspend_work); INIT_WORK(&hba->clk_scaling.resume_work, @@ -1874,7 +1893,7 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba) snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d", hba->host->host_no); hba->clk_gating.clk_gating_workq = alloc_ordered_workqueue(wq_name, - WQ_MEM_RECLAIM); + WQ_MEM_RECLAIM | WQ_HIGHPRI); hba->clk_gating.is_enabled = true; @@ -2557,6 +2576,14 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) (hba->clk_gating.state != CLKS_ON)); lrbp = &hba->lrb[tag]; + if (unlikely(lrbp->in_use)) { + if (hba->pm_op_in_progress) + set_host_byte(cmd, DID_BAD_TARGET); + else + err = SCSI_MLQUEUE_HOST_BUSY; + ufshcd_release(hba); + goto out; + } WARN_ON(lrbp->cmd); lrbp->cmd = cmd; @@ -2799,6 +2826,11 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, init_completion(&wait); lrbp = &hba->lrb[tag]; + if (unlikely(lrbp->in_use)) { + err = -EBUSY; + goto out; + } + WARN_ON(lrbp->cmd); err = ufshcd_compose_dev_cmd(hba, lrbp, cmd_type, tag); if (unlikely(err)) @@ -2815,6 +2847,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout); +out: ufshcd_add_query_upiu_trace(hba, tag, err ? "query_complete_err" : "query_complete"); @@ -2960,14 +2993,14 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, BUG_ON(!hba); - ufshcd_hold(hba, false); if (!attr_val) { dev_err(hba->dev, "%s: attribute value required for opcode 0x%x\n", __func__, opcode); - err = -EINVAL; - goto out; + return -EINVAL; } + ufshcd_hold(hba, false); + mutex_lock(&hba->dev_cmd.lock); ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector); @@ -2999,7 +3032,6 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, out_unlock: mutex_unlock(&hba->dev_cmd.lock); -out: ufshcd_release(hba); return err; } @@ -3051,21 +3083,20 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, BUG_ON(!hba); - ufshcd_hold(hba, false); if (!desc_buf) { dev_err(hba->dev, "%s: descriptor buffer required for opcode 0x%x\n", __func__, opcode); - err = -EINVAL; - goto out; + return -EINVAL; } if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n", __func__, *buf_len); - err = -EINVAL; - goto out; + return -EINVAL; } + ufshcd_hold(hba, false); + mutex_lock(&hba->dev_cmd.lock); ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector); @@ -3100,7 +3131,6 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, out_unlock: hba->dev_cmd.query.descriptor = NULL; mutex_unlock(&hba->dev_cmd.lock); -out: ufshcd_release(hba); return err; } @@ -3601,6 +3631,22 @@ static int ufshcd_dme_reset(struct ufs_hba *hba) return ret; } +int ufshcd_dme_configure_adapt(struct ufs_hba *hba, + int agreed_gear, + int adapt_val) +{ + int ret; + + if (agreed_gear != UFS_HS_G4) + adapt_val = PA_NO_ADAPT; + + ret = ufshcd_dme_set(hba, + UIC_ARG_MIB(PA_TXHSADAPTTYPE), + adapt_val); + return ret; +} +EXPORT_SYMBOL_GPL(ufshcd_dme_configure_adapt); + /** * ufshcd_dme_enable - UIC command for DME_ENABLE * @hba: per adapter instance @@ -3854,7 +3900,7 @@ out: if (ret) { ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); - ufshcd_print_host_regs(hba); + ufshcd_print_evt_hist(hba); } spin_lock_irqsave(hba->host->host_lock, flags); @@ -4350,8 +4396,10 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba) */ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) { - int retry; + int retry_outer = 3; + int retry_inner; +start: if (!ufshcd_is_hba_active(hba)) /* change controller state to "reset state" */ ufshcd_hba_stop(hba); @@ -4377,13 +4425,17 @@ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) ufshcd_delay_us(hba->vps->hba_enable_delay_us, 100); /* wait for the host controller to complete initialization */ - retry = 50; + retry_inner = 50; while (ufshcd_is_hba_active(hba)) { - if (retry) { - retry--; + if (retry_inner) { + retry_inner--; } else { dev_err(hba->dev, "Controller enable failed\n"); + if (retry_outer) { + retry_outer--; + goto start; + } return -EIO; } usleep_range(1000, 1100); @@ -4460,14 +4512,21 @@ static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba) return ufshcd_disable_tx_lcc(hba, true); } -void ufshcd_update_reg_hist(struct ufs_err_reg_hist *reg_hist, - u32 reg) +void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val) { - reg_hist->reg[reg_hist->pos] = reg; - reg_hist->tstamp[reg_hist->pos] = ktime_get(); - reg_hist->pos = (reg_hist->pos + 1) % UFS_ERR_REG_HIST_LENGTH; + struct ufs_event_hist *e; + + if (id >= UFS_EVT_CNT) + return; + + e = &hba->ufs_stats.event[id]; + e->val[e->pos] = val; + e->tstamp[e->pos] = ktime_get(); + e->pos = (e->pos + 1) % UFS_EVENT_HIST_LENGTH; + + ufshcd_vops_event_notify(hba, id, &val); } -EXPORT_SYMBOL_GPL(ufshcd_update_reg_hist); +EXPORT_SYMBOL_GPL(ufshcd_update_evt_hist); /** * ufshcd_link_startup - Initialize unipro link startup @@ -4496,7 +4555,8 @@ link_startup: /* check if device is detected by inter-connect layer */ if (!ret && !ufshcd_is_device_present(hba)) { - ufshcd_update_reg_hist(&hba->ufs_stats.link_startup_err, + ufshcd_update_evt_hist(hba, + UFS_EVT_LINK_STARTUP_FAIL, 0); dev_err(hba->dev, "%s: Device not present\n", __func__); ret = -ENXIO; @@ -4509,7 +4569,8 @@ link_startup: * succeeds. So reset the local Uni-Pro and try again. */ if (ret && ufshcd_hba_enable(hba)) { - ufshcd_update_reg_hist(&hba->ufs_stats.link_startup_err, + ufshcd_update_evt_hist(hba, + UFS_EVT_LINK_STARTUP_FAIL, (u32)ret); goto out; } @@ -4517,7 +4578,8 @@ link_startup: if (ret) { /* failed to get the link up... retire */ - ufshcd_update_reg_hist(&hba->ufs_stats.link_startup_err, + ufshcd_update_evt_hist(hba, + UFS_EVT_LINK_STARTUP_FAIL, (u32)ret); goto out; } @@ -4551,7 +4613,7 @@ out: dev_err(hba->dev, "link startup failed %d\n", ret); ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); - ufshcd_print_host_regs(hba); + ufshcd_print_evt_hist(hba); } return ret; } @@ -4906,7 +4968,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) dev_err(hba->dev, "OCS error from controller = %x for tag %d\n", ocs, lrbp->task_tag); - ufshcd_print_host_regs(hba); + ufshcd_print_evt_hist(hba); ufshcd_print_host_state(hba); break; } /* end of switch */ @@ -4964,9 +5026,11 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, struct scsi_cmnd *cmd; int result; int index; + bool update_scaling = false; for_each_set_bit(index, &completed_reqs, hba->nutrs) { lrbp = &hba->lrb[index]; + lrbp->in_use = false; lrbp->compl_time_stamp = ktime_get(); cmd = lrbp->cmd; if (cmd) { @@ -4979,15 +5043,17 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); __ufshcd_release(hba); + update_scaling = true; } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) { if (hba->dev_cmd.complete) { ufshcd_add_command_trace(hba, index, "dev_complete"); complete(hba->dev_cmd.complete); + update_scaling = true; } } - if (ufshcd_is_clkscaling_supported(hba)) + if (ufshcd_is_clkscaling_supported(hba) && update_scaling) hba->clk_scaling.active_reqs--; } @@ -5632,7 +5698,9 @@ static inline void ufshcd_schedule_eh_work(struct ufs_hba *hba) static void ufshcd_err_handling_prepare(struct ufs_hba *hba) { pm_runtime_get_sync(hba->dev); - if (pm_runtime_suspended(hba->dev)) { + if (pm_runtime_status_suspended(hba->dev) || hba->is_sys_suspended) { + enum ufs_pm_op pm_op; + /* * Don't assume anything of pm_runtime_get_sync(), if * resume fails, irq and clocks can be OFF, and powers @@ -5647,7 +5715,8 @@ static void ufshcd_err_handling_prepare(struct ufs_hba *hba) if (!ufshcd_is_clkgating_allowed(hba)) ufshcd_setup_clocks(hba, true); ufshcd_release(hba); - ufshcd_vops_resume(hba, UFS_RUNTIME_PM); + pm_op = hba->is_sys_suspended ? UFS_SYSTEM_PM : UFS_RUNTIME_PM; + ufshcd_vops_resume(hba, pm_op); } else { ufshcd_hold(hba, false); if (hba->clk_scaling.is_allowed) { @@ -5668,7 +5737,7 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba) { - return (hba->ufshcd_state == UFSHCD_STATE_ERROR || + return (!hba->is_powered || hba->ufshcd_state == UFSHCD_STATE_ERROR || (!(hba->saved_err || hba->saved_uic_err || hba->force_reset || ufshcd_is_link_broken(hba)))); } @@ -5681,6 +5750,7 @@ static void ufshcd_recover_pm_error(struct ufs_hba *hba) struct request_queue *q; int ret; + hba->is_sys_suspended = false; /* * Set RPM status of hba device to RPM_ACTIVE, * this also clears its runtime error. @@ -5739,11 +5809,13 @@ static void ufshcd_err_handler(struct work_struct *work) hba = container_of(work, struct ufs_hba, eh_work); + down(&hba->eh_sem); spin_lock_irqsave(hba->host->host_lock, flags); if (ufshcd_err_handling_should_stop(hba)) { if (hba->ufshcd_state != UFSHCD_STATE_ERROR) hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; spin_unlock_irqrestore(hba->host->host_lock, flags); + up(&hba->eh_sem); return; } ufshcd_set_eh_in_progress(hba); @@ -5751,20 +5823,18 @@ static void ufshcd_err_handler(struct work_struct *work) ufshcd_err_handling_prepare(hba); spin_lock_irqsave(hba->host->host_lock, flags); ufshcd_scsi_block_requests(hba); - /* - * A full reset and restore might have happened after preparation - * is finished, double check whether we should stop. - */ - if (ufshcd_err_handling_should_stop(hba)) { - if (hba->ufshcd_state != UFSHCD_STATE_ERROR) - hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; - goto out; - } hba->ufshcd_state = UFSHCD_STATE_RESET; /* Complete requests that have door-bell cleared by h/w */ ufshcd_complete_requests(hba); + /* + * A full reset and restore might have happened after preparation + * is finished, double check whether we should stop. + */ + if (ufshcd_err_handling_should_stop(hba)) + goto skip_err_handling; + if (hba->dev_quirks & UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) { bool ret; @@ -5772,17 +5842,10 @@ static void ufshcd_err_handler(struct work_struct *work) /* release the lock as ufshcd_quirk_dl_nac_errors() may sleep */ ret = ufshcd_quirk_dl_nac_errors(hba); spin_lock_irqsave(hba->host->host_lock, flags); - if (!ret && !hba->force_reset && ufshcd_is_link_active(hba)) + if (!ret && ufshcd_err_handling_should_stop(hba)) goto skip_err_handling; } - if (hba->force_reset || ufshcd_is_link_broken(hba) || - ufshcd_is_saved_err_fatal(hba) || - ((hba->saved_err & UIC_ERROR) && - (hba->saved_uic_err & (UFSHCD_UIC_DL_NAC_RECEIVED_ERROR | - UFSHCD_UIC_DL_TCx_REPLAY_ERROR)))) - needs_reset = true; - if ((hba->saved_err & (INT_FATAL_ERRORS | UFSHCD_UIC_HIBERN8_MASK)) || (hba->saved_uic_err && (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) { @@ -5791,7 +5854,7 @@ static void ufshcd_err_handler(struct work_struct *work) spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); - ufshcd_print_host_regs(hba); + ufshcd_print_evt_hist(hba); ufshcd_print_tmrs(hba, hba->outstanding_tasks); ufshcd_print_trs(hba, hba->outstanding_reqs, pr_prdt); spin_lock_irqsave(hba->host->host_lock, flags); @@ -5802,8 +5865,14 @@ static void ufshcd_err_handler(struct work_struct *work) * transfers forcefully because they will get cleared during * host reset and restore */ - if (needs_reset) + if (hba->force_reset || ufshcd_is_link_broken(hba) || + ufshcd_is_saved_err_fatal(hba) || + ((hba->saved_err & UIC_ERROR) && + (hba->saved_uic_err & (UFSHCD_UIC_DL_NAC_RECEIVED_ERROR | + UFSHCD_UIC_DL_TCx_REPLAY_ERROR)))) { + needs_reset = true; goto do_reset; + } /* * If LINERESET was caught, UFS might have been put to PWM mode, @@ -5911,12 +5980,11 @@ skip_err_handling: dev_err_ratelimited(hba->dev, "%s: exit: saved_err 0x%x saved_uic_err 0x%x", __func__, hba->saved_err, hba->saved_uic_err); } - -out: ufshcd_clear_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_scsi_unblock_requests(hba); ufshcd_err_handling_unprepare(hba); + up(&hba->eh_sem); } /** @@ -5936,7 +6004,7 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) { - ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg); + ufshcd_update_evt_hist(hba, UFS_EVT_PA_ERR, reg); /* * To know whether this error is fatal or not, DB timeout * must be checked but this error is handled separately. @@ -5966,7 +6034,7 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER); if ((reg & UIC_DATA_LINK_LAYER_ERROR) && (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) { - ufshcd_update_reg_hist(&hba->ufs_stats.dl_err, reg); + ufshcd_update_evt_hist(hba, UFS_EVT_DL_ERR, reg); if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR; @@ -5985,7 +6053,7 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER); if ((reg & UIC_NETWORK_LAYER_ERROR) && (reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK)) { - ufshcd_update_reg_hist(&hba->ufs_stats.nl_err, reg); + ufshcd_update_evt_hist(hba, UFS_EVT_NL_ERR, reg); hba->uic_error |= UFSHCD_UIC_NL_ERROR; retval |= IRQ_HANDLED; } @@ -5993,7 +6061,7 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER); if ((reg & UIC_TRANSPORT_LAYER_ERROR) && (reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK)) { - ufshcd_update_reg_hist(&hba->ufs_stats.tl_err, reg); + ufshcd_update_evt_hist(hba, UFS_EVT_TL_ERR, reg); hba->uic_error |= UFSHCD_UIC_TL_ERROR; retval |= IRQ_HANDLED; } @@ -6001,7 +6069,7 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME); if ((reg & UIC_DME_ERROR) && (reg & UIC_DME_ERROR_CODE_MASK)) { - ufshcd_update_reg_hist(&hba->ufs_stats.dme_err, reg); + ufshcd_update_evt_hist(hba, UFS_EVT_DME_ERR, reg); hba->uic_error |= UFSHCD_UIC_DME_ERROR; retval |= IRQ_HANDLED; } @@ -6043,7 +6111,8 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba) irqreturn_t retval = IRQ_NONE; if (hba->errors & INT_FATAL_ERRORS) { - ufshcd_update_reg_hist(&hba->ufs_stats.fatal_err, hba->errors); + ufshcd_update_evt_hist(hba, UFS_EVT_FATAL_ERR, + hba->errors); queue_eh_work = true; } @@ -6060,7 +6129,7 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba) __func__, (hba->errors & UIC_HIBERNATE_ENTER) ? "Enter" : "Exit", hba->errors, ufshcd_get_upmcrs(hba)); - ufshcd_update_reg_hist(&hba->ufs_stats.auto_hibern8_err, + ufshcd_update_evt_hist(hba, UFS_EVT_AUTO_HIBERN8_ERR, hba->errors); ufshcd_set_link_broken(hba); queue_eh_work = true; @@ -6075,7 +6144,8 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba) hba->saved_uic_err |= hba->uic_error; /* dump controller state before resetting */ - if ((hba->saved_err & (INT_FATAL_ERRORS)) || + if ((hba->saved_err & + (INT_FATAL_ERRORS | UFSHCD_UIC_HIBERN8_MASK)) || (hba->saved_uic_err && (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) { dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x\n", @@ -6407,8 +6477,12 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, init_completion(&wait); lrbp = &hba->lrb[tag]; - WARN_ON(lrbp->cmd); + if (unlikely(lrbp->in_use)) { + err = -EBUSY; + goto out; + } + WARN_ON(lrbp->cmd); lrbp->cmd = NULL; lrbp->sense_bufflen = 0; lrbp->sense_buffer = NULL; @@ -6480,6 +6554,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, } } +out: blk_put_request(req); out_unlock: up_read(&hba->clk_scaling_lock); @@ -6601,7 +6676,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd) out: hba->req_abort_count = 0; - ufshcd_update_reg_hist(&hba->ufs_stats.dev_reset, (u32)err); + ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, (u32)err); if (!err) { err = SUCCESS; } else { @@ -6624,7 +6699,8 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap) /** * ufshcd_try_to_abort_task - abort a specific task - * @cmd: SCSI command pointer + * @hba: Pointer to adapter instance + * @tag: Task tag/index to be aborted * * Abort the pending command in device by sending UFS_ABORT_TASK task management * command, and in host controller by clearing the door-bell register. There can @@ -6729,16 +6805,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) BUG(); } - /* - * Task abort to the device W-LUN is illegal. When this command - * will fail, due to spec violation, scsi err handling next step - * will be to send LU reset which, again, is a spec violation. - * To avoid these unnecessary/illegal step we skip to the last error - * handling stage: reset and restore. - */ - if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN) - return ufshcd_eh_host_reset_handler(cmd); - ufshcd_hold(hba, false); reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); /* If command is already aborted/completed, return SUCCESS */ @@ -6759,10 +6825,10 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) * to reduce repeated printouts. For other aborted requests only print * basic details. */ - scsi_print_command(hba->lrb[tag].cmd); + scsi_print_command(cmd); if (!hba->req_abort_count) { - ufshcd_update_reg_hist(&hba->ufs_stats.task_abort, 0); - ufshcd_print_host_regs(hba); + ufshcd_update_evt_hist(hba, UFS_EVT_ABORT, tag); + ufshcd_print_evt_hist(hba); ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); ufshcd_print_trs(hba, 1 << tag, true); @@ -6778,6 +6844,29 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) goto cleanup; } + /* + * Task abort to the device W-LUN is illegal. When this command + * will fail, due to spec violation, scsi err handling next step + * will be to send LU reset which, again, is a spec violation. + * To avoid these unnecessary/illegal steps, first we clean up + * the lrb taken by this cmd and mark the lrb as in_use, then + * queue the eh_work and bail. + */ + if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN) { + ufshcd_update_evt_hist(hba, UFS_EVT_ABORT, lrbp->lun); + spin_lock_irqsave(host->host_lock, flags); + if (lrbp->cmd) { + __ufshcd_transfer_req_compl(hba, (1UL << tag)); + __set_bit(tag, &hba->outstanding_reqs); + lrbp->in_use = true; + hba->force_reset = true; + ufshcd_schedule_eh_work(hba); + } + + spin_unlock_irqrestore(host->host_lock, flags); + goto out; + } + /* Skip task abort in case previous aborts failed and report failure */ if (lrbp->req_abort_skip) err = -EIO; @@ -6845,7 +6934,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) out: if (err) dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err); - ufshcd_update_reg_hist(&hba->ufs_stats.host_reset, (u32)err); + ufshcd_update_evt_hist(hba, UFS_EVT_HOST_RESET, (u32)err); return err; } @@ -6891,6 +6980,7 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) */ scsi_report_bus_reset(hba->host, 0); if (err) { + hba->ufshcd_state = UFSHCD_STATE_ERROR; hba->saved_err |= saved_err; hba->saved_uic_err |= saved_uic_err; } @@ -7092,7 +7182,6 @@ static inline void ufshcd_blk_pm_runtime_init(struct scsi_device *sdev) static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) { int ret = 0; - struct scsi_device *sdev_rpmb; struct scsi_device *sdev_boot; hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0, @@ -7105,14 +7194,14 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) ufshcd_blk_pm_runtime_init(hba->sdev_ufs_device); scsi_device_put(hba->sdev_ufs_device); - sdev_rpmb = __scsi_add_device(hba->host, 0, 0, + hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0, ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL); - if (IS_ERR(sdev_rpmb)) { - ret = PTR_ERR(sdev_rpmb); + if (IS_ERR(hba->sdev_rpmb)) { + ret = PTR_ERR(hba->sdev_rpmb); goto remove_sdev_ufs_device; } - ufshcd_blk_pm_runtime_init(sdev_rpmb); - scsi_device_put(sdev_rpmb); + ufshcd_blk_pm_runtime_init(hba->sdev_rpmb); + scsi_device_put(hba->sdev_rpmb); sdev_boot = __scsi_add_device(hba->host, 0, 0, ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL); @@ -7636,6 +7725,63 @@ out: return ret; } +static int +ufshcd_send_request_sense(struct ufs_hba *hba, struct scsi_device *sdp); + +static int ufshcd_clear_ua_wlun(struct ufs_hba *hba, u8 wlun) +{ + struct scsi_device *sdp; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(hba->host->host_lock, flags); + if (wlun == UFS_UPIU_UFS_DEVICE_WLUN) + sdp = hba->sdev_ufs_device; + else if (wlun == UFS_UPIU_RPMB_WLUN) + sdp = hba->sdev_rpmb; + else + BUG(); + if (sdp) { + ret = scsi_device_get(sdp); + if (!ret && !scsi_device_online(sdp)) { + ret = -ENODEV; + scsi_device_put(sdp); + } + } else { + ret = -ENODEV; + } + spin_unlock_irqrestore(hba->host->host_lock, flags); + if (ret) + goto out_err; + + ret = ufshcd_send_request_sense(hba, sdp); + scsi_device_put(sdp); +out_err: + if (ret) + dev_err(hba->dev, "%s: UAC clear LU=%x ret = %d\n", + __func__, wlun, ret); + return ret; +} + +static int ufshcd_clear_ua_wluns(struct ufs_hba *hba) +{ + int ret = 0; + + if (!hba->wlun_dev_clr_ua) + goto out; + + ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN); + if (!ret) + ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_RPMB_WLUN); + if (!ret) + hba->wlun_dev_clr_ua = false; +out: + if (ret) + dev_err(hba->dev, "%s: Failed to clear UAC WLUNS ret = %d\n", + __func__, ret); + return ret; +} + /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance @@ -7739,8 +7885,10 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie) struct ufs_hba *hba = (struct ufs_hba *)data; int ret; + down(&hba->eh_sem); /* Initialize hba, detect and initialize UFS device */ ret = ufshcd_probe_hba(hba, true); + up(&hba->eh_sem); if (ret) goto out; @@ -7755,6 +7903,8 @@ out: pm_runtime_put_sync(hba->dev); ufshcd_exit_clk_scaling(hba); ufshcd_hba_exit(hba); + } else { + ufshcd_clear_ua_wluns(hba); } } @@ -7988,8 +8138,7 @@ static int ufshcd_init_hba_vreg(struct ufs_hba *hba) return 0; } -static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, - bool skip_ref_clk) +static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on) { int ret = 0; struct ufs_clk_info *clki; @@ -8007,7 +8156,12 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, list_for_each_entry(clki, head, list) { if (!IS_ERR_OR_NULL(clki->clk)) { - if (skip_ref_clk && !strcmp(clki->name, "ref_clk")) + /* + * Don't disable clocks which are needed + * to keep the link active. + */ + if (ufshcd_is_link_active(hba) && + clki->keep_link_active) continue; clk_state_changed = on ^ clki->enabled; @@ -8052,11 +8206,6 @@ out: return ret; } -static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on) -{ - return __ufshcd_setup_clocks(hba, on, false); -} - static int ufshcd_init_clocks(struct ufs_hba *hba) { int ret = 0; @@ -8113,15 +8262,9 @@ static int ufshcd_variant_hba_init(struct ufs_hba *hba) err = ufshcd_vops_init(hba); if (err) - goto out; - - err = ufshcd_vops_setup_regulators(hba, true); - if (err) - ufshcd_vops_exit(hba); -out: - if (err) dev_err(hba->dev, "%s: variant %s init failed err %d\n", __func__, ufshcd_get_var_name(hba), err); +out: return err; } @@ -8130,8 +8273,6 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba) if (!hba->vops) return; - ufshcd_vops_setup_regulators(hba, false); - ufshcd_vops_exit(hba); } @@ -8327,7 +8468,8 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba, } /* * If autobkops is enabled, link can't be turned off because - * turning off the link would also turn off the device. + * turning off the link would also turn off the device, except in the + * case of DeepSleep where the device is expected to remain powered. */ else if ((req_link_state == UIC_LINK_OFF_STATE) && (!check_for_bkops || !hba->auto_bkops_enabled)) { @@ -8337,6 +8479,9 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba, * put the link in low power mode is to send the DME end point * to device and then send the DME reset command to local * unipro. But putting the link in hibern8 is much faster. + * + * Note also that putting the link in Hibern8 is a requirement + * for entering DeepSleep. */ ret = ufshcd_uic_hibern8_enter(hba); if (ret) { @@ -8440,13 +8585,13 @@ out: static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba) { - if (ufshcd_is_link_off(hba)) + if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba)) ufshcd_setup_hba_vreg(hba, false); } static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba) { - if (ufshcd_is_link_off(hba)) + if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba)) ufshcd_setup_hba_vreg(hba, true); } @@ -8469,6 +8614,7 @@ static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba) static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) { int ret = 0; + int check_for_bkops; enum ufs_pm_level pm_lvl; enum ufs_dev_pwr_mode req_dev_pwr_mode; enum uic_link_state req_link_state; @@ -8540,11 +8686,9 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) } if (req_dev_pwr_mode != hba->curr_dev_pwr_mode) { - if ((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) || - !ufshcd_is_runtime_pm(pm_op)) { + if (!ufshcd_is_runtime_pm(pm_op)) /* ensure that bkops is disabled */ ufshcd_disable_auto_bkops(hba); - } if (!hba->dev_info.b_rpm_dev_flush_capable) { ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode); @@ -8554,7 +8698,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) } flush_work(&hba->eeh_work); - ret = ufshcd_link_state_transition(hba, req_link_state, 1); + + /* + * In the case of DeepSleep, the device is expected to remain powered + * with the link off, so do not check for bkops. + */ + check_for_bkops = !ufshcd_is_ufs_dev_deepsleep(hba); + ret = ufshcd_link_state_transition(hba, req_link_state, check_for_bkops); if (ret) goto set_dev_active; @@ -8575,11 +8725,7 @@ disable_clks: */ ufshcd_disable_irq(hba); - if (!ufshcd_is_link_active(hba)) - ufshcd_setup_clocks(hba, false); - else - /* If link is active, device ref_clk can't be switched off */ - __ufshcd_setup_clocks(hba, false, true); + ufshcd_setup_clocks(hba, false); if (ufshcd_is_clkgating_allowed(hba)) { hba->clk_gating.state = CLKS_OFF; @@ -8595,11 +8741,25 @@ set_link_active: if (hba->clk_scaling.is_allowed) ufshcd_resume_clkscaling(hba); ufshcd_vreg_set_hpm(hba); + /* + * Device hardware reset is required to exit DeepSleep. Also, for + * DeepSleep, the link is off so host reset and restore will be done + * further below. + */ + if (ufshcd_is_ufs_dev_deepsleep(hba)) { + ufshcd_vops_device_reset(hba); + WARN_ON(!ufshcd_is_link_off(hba)); + } if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba)) ufshcd_set_link_active(hba); else if (ufshcd_is_link_off(hba)) ufshcd_host_reset_and_restore(hba); set_dev_active: + /* Can also get here needing to exit DeepSleep */ + if (ufshcd_is_ufs_dev_deepsleep(hba)) { + ufshcd_vops_device_reset(hba); + ufshcd_host_reset_and_restore(hba); + } if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE)) ufshcd_disable_auto_bkops(hba); enable_gating: @@ -8617,7 +8777,7 @@ out: hba->pm_op_in_progress = 0; if (ret) - ufshcd_update_reg_hist(&hba->ufs_stats.suspend_err, (u32)ret); + ufshcd_update_evt_hist(hba, UFS_EVT_SUSPEND_ERR, (u32)ret); return ret; } @@ -8661,6 +8821,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ret) goto disable_vreg; + /* For DeepSleep, the only supported option is to have the link off */ + WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) && !ufshcd_is_link_off(hba)); + if (ufshcd_is_link_hibern8(hba)) { ret = ufshcd_uic_hibern8_exit(hba); if (!ret) { @@ -8674,6 +8837,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) /* * A full initialization of the host and the device is * required since the link was put to off during suspend. + * Note, in the case of DeepSleep, the device will exit + * DeepSleep due to device reset. */ ret = ufshcd_reset_and_restore(hba); /* @@ -8736,7 +8901,7 @@ disable_irq_and_vops_clks: out: hba->pm_op_in_progress = 0; if (ret) - ufshcd_update_reg_hist(&hba->ufs_stats.resume_err, (u32)ret); + ufshcd_update_evt_hist(hba, UFS_EVT_RESUME_ERR, (u32)ret); return ret; } @@ -8753,6 +8918,7 @@ int ufshcd_system_suspend(struct ufs_hba *hba) int ret = 0; ktime_t start = ktime_get(); + down(&hba->eh_sem); if (!hba || !hba->is_powered) return 0; @@ -8783,6 +8949,8 @@ out: hba->curr_dev_pwr_mode, hba->uic_link_state); if (!ret) hba->is_sys_suspended = true; + else + up(&hba->eh_sem); return ret; } EXPORT_SYMBOL(ufshcd_system_suspend); @@ -8799,8 +8967,10 @@ int ufshcd_system_resume(struct ufs_hba *hba) int ret = 0; ktime_t start = ktime_get(); - if (!hba) + if (!hba) { + up(&hba->eh_sem); return -EINVAL; + } if (!hba->is_powered || pm_runtime_suspended(hba->dev)) /* @@ -8816,6 +8986,7 @@ out: hba->curr_dev_pwr_mode, hba->uic_link_state); if (!ret) hba->is_sys_suspended = false; + up(&hba->eh_sem); return ret; } EXPORT_SYMBOL(ufshcd_system_resume); @@ -8907,6 +9078,7 @@ int ufshcd_shutdown(struct ufs_hba *hba) { int ret = 0; + down(&hba->eh_sem); if (!hba->is_powered) goto out; @@ -8919,6 +9091,8 @@ int ufshcd_shutdown(struct ufs_hba *hba) out: if (ret) dev_err(hba->dev, "%s failed, err %d\n", __func__, ret); + hba->is_powered = false; + up(&hba->eh_sem); /* allow force shutdown even in case of errors */ return 0; } @@ -9114,6 +9288,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) INIT_WORK(&hba->eh_work, ufshcd_err_handler); INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler); + sema_init(&hba->eh_sem, 1); + /* Initialize UIC command mutex */ mutex_init(&hba->uic_cmd_mutex); @@ -9185,7 +9361,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) err = ufshcd_hba_enable(hba); if (err) { dev_err(hba->dev, "Host controller enable failed\n"); - ufshcd_print_host_regs(hba); + ufshcd_print_evt_hist(hba); ufshcd_print_host_state(hba); goto free_tmf_queue; } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index e0f00a42371c..f8c2467dc014 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -58,6 +58,29 @@ enum dev_cmd_type { DEV_CMD_TYPE_QUERY = 0x1, }; +enum ufs_event_type { + /* uic specific errors */ + UFS_EVT_PA_ERR = 0, + UFS_EVT_DL_ERR, + UFS_EVT_NL_ERR, + UFS_EVT_TL_ERR, + UFS_EVT_DME_ERR, + + /* fatal errors */ + UFS_EVT_AUTO_HIBERN8_ERR, + UFS_EVT_FATAL_ERR, + UFS_EVT_LINK_STARTUP_FAIL, + UFS_EVT_RESUME_ERR, + UFS_EVT_SUSPEND_ERR, + + /* abnormal events */ + UFS_EVT_DEV_RESET, + UFS_EVT_HOST_RESET, + UFS_EVT_ABORT, + + UFS_EVT_CNT, +}; + /** * struct uic_command - UIC command structure * @command: UIC command @@ -116,16 +139,22 @@ enum uic_link_state { ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE) #define ufshcd_set_ufs_dev_poweroff(h) \ ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE) +#define ufshcd_set_ufs_dev_deepsleep(h) \ + ((h)->curr_dev_pwr_mode = UFS_DEEPSLEEP_PWR_MODE) #define ufshcd_is_ufs_dev_active(h) \ ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE) #define ufshcd_is_ufs_dev_sleep(h) \ ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE) #define ufshcd_is_ufs_dev_poweroff(h) \ ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE) +#define ufshcd_is_ufs_dev_deepsleep(h) \ + ((h)->curr_dev_pwr_mode == UFS_DEEPSLEEP_PWR_MODE) /* * UFS Power management levels. - * Each level is in increasing order of power savings. + * Each level is in increasing order of power savings, except DeepSleep + * which is lower than PowerDown with power on but not PowerDown with + * power off. */ enum ufs_pm_level { UFS_PM_LVL_0, /* UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE */ @@ -134,6 +163,7 @@ enum ufs_pm_level { UFS_PM_LVL_3, /* UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_4, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_5, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE */ + UFS_PM_LVL_6, /* UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE */ UFS_PM_LVL_MAX }; @@ -165,6 +195,7 @@ struct ufs_pm_lvl_states { * @crypto_key_slot: the key slot to use for inline crypto (-1 if none) * @data_unit_num: the data unit number for the first block for inline crypto * @req_abort_skip: skip request abort task flag + * @in_use: indicates that this lrb is still in use */ struct ufshcd_lrb { struct utp_transfer_req_desc *utr_descriptor_ptr; @@ -194,6 +225,7 @@ struct ufshcd_lrb { #endif bool req_abort_skip; + bool in_use; }; /** @@ -229,6 +261,8 @@ struct ufs_dev_cmd { * @max_freq: maximum frequency supported by the clock * @min_freq: min frequency that can be used for clock scaling * @curr_freq: indicates the current frequency that it is set to + * @keep_link_active: indicates that the clk should not be disabled if + link is active * @enabled: variable to check against multiple enable/disable */ struct ufs_clk_info { @@ -238,6 +272,7 @@ struct ufs_clk_info { u32 max_freq; u32 min_freq; u32 curr_freq; + bool keep_link_active; bool enabled; }; @@ -269,7 +304,6 @@ struct ufs_pwr_mode_info { * @get_ufs_hci_version: called to get UFS HCI version * @clk_scale_notify: notifies that clks are scaled up/down * @setup_clocks: called before touching any of the controller registers - * @setup_regulators: called before accessing the host controller * @hce_enable_notify: called before and after HCE enable bit is set to allow * variant specific Uni-Pro initialization. * @link_startup_notify: called before and after Link startup is carried out @@ -289,6 +323,7 @@ struct ufs_pwr_mode_info { * @phy_initialization: used to initialize phys * @device_reset: called to issue a reset pulse on the UFS device * @program_key: program or evict an inline encryption key + * @event_notify: called to notify important events */ struct ufs_hba_variant_ops { const char *name; @@ -299,7 +334,6 @@ struct ufs_hba_variant_ops { enum ufs_notify_change_status); int (*setup_clocks)(struct ufs_hba *, bool, enum ufs_notify_change_status); - int (*setup_regulators)(struct ufs_hba *, bool); int (*hce_enable_notify)(struct ufs_hba *, enum ufs_notify_change_status); int (*link_startup_notify)(struct ufs_hba *, @@ -318,12 +352,14 @@ struct ufs_hba_variant_ops { int (*resume)(struct ufs_hba *, enum ufs_pm_op); void (*dbg_register_dump)(struct ufs_hba *hba); int (*phy_initialization)(struct ufs_hba *); - void (*device_reset)(struct ufs_hba *hba); + int (*device_reset)(struct ufs_hba *hba); void (*config_scaling_param)(struct ufs_hba *hba, struct devfreq_dev_profile *profile, void *data); int (*program_key)(struct ufs_hba *hba, const union ufs_crypto_cfg_entry *cfg, int slot); + void (*event_notify)(struct ufs_hba *hba, + enum ufs_event_type evt, void *data); }; /* clock gating state */ @@ -382,6 +418,7 @@ struct ufs_saved_pwr_info { * @workq: workqueue to schedule devfreq suspend/resume work * @suspend_work: worker to suspend devfreq * @resume_work: worker to resume devfreq + * @min_gear: lowest HS gear to scale down to * @is_allowed: tracks if scaling is currently allowed or not * @is_busy_started: tracks if busy period has started or not * @is_suspended: tracks if devfreq is suspended or not @@ -396,22 +433,23 @@ struct ufs_clk_scaling { struct workqueue_struct *workq; struct work_struct suspend_work; struct work_struct resume_work; + u32 min_gear; bool is_allowed; bool is_busy_started; bool is_suspended; }; -#define UFS_ERR_REG_HIST_LENGTH 8 +#define UFS_EVENT_HIST_LENGTH 8 /** - * struct ufs_err_reg_hist - keeps history of errors + * struct ufs_event_hist - keeps history of errors * @pos: index to indicate cyclic buffer position * @reg: cyclic buffer for registers value * @tstamp: cyclic buffer for time stamp */ -struct ufs_err_reg_hist { +struct ufs_event_hist { int pos; - u32 reg[UFS_ERR_REG_HIST_LENGTH]; - ktime_t tstamp[UFS_ERR_REG_HIST_LENGTH]; + u32 val[UFS_EVENT_HIST_LENGTH]; + ktime_t tstamp[UFS_EVENT_HIST_LENGTH]; }; /** @@ -422,19 +460,6 @@ struct ufs_err_reg_hist { * reset this after link-startup. * @last_hibern8_exit_tstamp: Set time after the hibern8 exit. * Clear after the first successful command completion. - * @pa_err: tracks pa-uic errors - * @dl_err: tracks dl-uic errors - * @nl_err: tracks nl-uic errors - * @tl_err: tracks tl-uic errors - * @dme_err: tracks dme errors - * @auto_hibern8_err: tracks auto-hibernate errors - * @fatal_err: tracks fatal errors - * @linkup_err: tracks link-startup errors - * @resume_err: tracks resume errors - * @suspend_err: tracks suspend errors - * @dev_reset: tracks device reset events - * @host_reset: tracks host reset events - * @tsk_abort: tracks task abort events */ struct ufs_stats { u32 last_intr_status; @@ -442,25 +467,7 @@ struct ufs_stats { u32 hibern8_exit_cnt; ktime_t last_hibern8_exit_tstamp; - - /* uic specific errors */ - struct ufs_err_reg_hist pa_err; - struct ufs_err_reg_hist dl_err; - struct ufs_err_reg_hist nl_err; - struct ufs_err_reg_hist tl_err; - struct ufs_err_reg_hist dme_err; - - /* fatal errors */ - struct ufs_err_reg_hist auto_hibern8_err; - struct ufs_err_reg_hist fatal_err; - struct ufs_err_reg_hist link_startup_err; - struct ufs_err_reg_hist resume_err; - struct ufs_err_reg_hist suspend_err; - - /* abnormal events */ - struct ufs_err_reg_hist dev_reset; - struct ufs_err_reg_hist host_reset; - struct ufs_err_reg_hist task_abort; + struct ufs_event_hist event[UFS_EVT_CNT]; }; enum ufshcd_quirks { @@ -594,6 +601,21 @@ enum ufshcd_caps { * inline crypto engine, if it is present */ UFSHCD_CAP_CRYPTO = 1 << 8, + + /* + * This capability allows the controller regulators to be put into + * lpm mode aggressively during clock gating. + * This would increase power savings. + */ + UFSHCD_CAP_AGGR_POWER_COLLAPSE = 1 << 9, + + /* + * This capability allows the host controller driver to use DeepSleep, + * if it is supported by the UFS device. The host controller driver must + * support device hardware reset via the hba->device_reset() callback, + * in order to exit DeepSleep state. + */ + UFSHCD_CAP_DEEPSLEEP = 1 << 10, }; struct ufs_hba_variant_params { @@ -683,6 +705,7 @@ struct ufs_hba { * "UFS device" W-LU. */ struct scsi_device *sdev_ufs_device; + struct scsi_device *sdev_rpmb; enum ufs_dev_pwr_mode curr_dev_pwr_mode; enum uic_link_state uic_link_state; @@ -730,6 +753,7 @@ struct ufs_hba { u32 intr_mask; u16 ee_ctrl_mask; bool is_powered; + struct semaphore eh_sem; /* Work Queues */ struct workqueue_struct *eh_wq; @@ -831,6 +855,12 @@ return true; #endif } +static inline bool ufshcd_can_aggressive_pc(struct ufs_hba *hba) +{ + return !!(ufshcd_is_link_hibern8(hba) && + (hba->caps & UFSHCD_CAP_AGGR_POWER_COLLAPSE)); +} + static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba) { return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) && @@ -882,8 +912,7 @@ int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, u32 val, unsigned long interval_us, unsigned long timeout_ms); void ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk); -void ufshcd_update_reg_hist(struct ufs_err_reg_hist *reg_hist, - u32 reg); +void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val); static inline void check_upiu_size(void) { @@ -930,6 +959,9 @@ extern int ufshcd_runtime_idle(struct ufs_hba *hba); extern int ufshcd_system_suspend(struct ufs_hba *hba); extern int ufshcd_system_resume(struct ufs_hba *hba); extern int ufshcd_shutdown(struct ufs_hba *hba); +extern int ufshcd_dme_configure_adapt(struct ufs_hba *hba, + int agreed_gear, + int adapt_val); extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set, u32 mib_val, u8 peer); extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, @@ -1076,6 +1108,14 @@ static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba, return 0; } +static inline void ufshcd_vops_event_notify(struct ufs_hba *hba, + enum ufs_event_type evt, + void *data) +{ + if (hba->vops && hba->vops->event_notify) + hba->vops->event_notify(hba, evt, data); +} + static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) { @@ -1084,14 +1124,6 @@ static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on, return 0; } -static inline int ufshcd_vops_setup_regulators(struct ufs_hba *hba, bool status) -{ - if (hba->vops && hba->vops->setup_regulators) - return hba->vops->setup_regulators(hba, status); - - return 0; -} - static inline int ufshcd_vops_hce_enable_notify(struct ufs_hba *hba, bool status) { @@ -1109,6 +1141,14 @@ static inline int ufshcd_vops_link_startup_notify(struct ufs_hba *hba, return 0; } +static inline int ufshcd_vops_phy_initialization(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->phy_initialization) + return hba->vops->phy_initialization(hba); + + return 0; +} + static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba, bool status, struct ufs_pa_layer_attr *dev_max_params, @@ -1181,9 +1221,12 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) static inline void ufshcd_vops_device_reset(struct ufs_hba *hba) { if (hba->vops && hba->vops->device_reset) { - hba->vops->device_reset(hba); - ufshcd_set_ufs_dev_active(hba); - ufshcd_update_reg_hist(&hba->ufs_stats.dev_reset, 0); + int err = hba->vops->device_reset(hba); + + if (!err) + ufshcd_set_ufs_dev_active(hba); + if (err != -EOPNOTSUPP) + ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err); } } diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index f6b52ce36de6..8e9e486a4f7b 100644 --- a/drivers/scsi/ufs/unipro.h +++ b/drivers/scsi/ufs/unipro.h @@ -237,8 +237,10 @@ enum ufs_unipro_ver { UFS_UNIPRO_VER_RESERVED = 0, UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */ UFS_UNIPRO_VER_1_41 = 2, /* UniPro version 1.41 */ - UFS_UNIPRO_VER_1_6 = 3, /* UniPro version 1.6 */ - UFS_UNIPRO_VER_MAX = 4, /* UniPro unsupported version */ + UFS_UNIPRO_VER_1_6 = 3, /* UniPro version 1.6 */ + UFS_UNIPRO_VER_1_61 = 4, /* UniPro version 1.61 */ + UFS_UNIPRO_VER_1_8 = 5, /* UniPro version 1.8 */ + UFS_UNIPRO_VER_MAX = 6, /* UniPro unsupported version */ /* UniPro version field mask in PA_LOCALVERINFO */ UFS_UNIPRO_VER_MASK = 0xF, }; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 16d5a4e117a2..badba437e5f9 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -46,6 +46,15 @@ static int tcm_loop_hba_no_cnt; static int tcm_loop_queue_status(struct se_cmd *se_cmd); +static unsigned int tcm_loop_nr_hw_queues = 1; +module_param_named(nr_hw_queues, tcm_loop_nr_hw_queues, uint, 0644); + +static unsigned int tcm_loop_can_queue = 1024; +module_param_named(can_queue, tcm_loop_can_queue, uint, 0644); + +static unsigned int tcm_loop_cmd_per_lun = 1024; +module_param_named(cmd_per_lun, tcm_loop_cmd_per_lun, uint, 0644); + /* * Called from struct target_core_fabric_ops->check_stop_free() */ @@ -305,10 +314,8 @@ static struct scsi_host_template tcm_loop_driver_template = { .eh_abort_handler = tcm_loop_abort_task, .eh_device_reset_handler = tcm_loop_device_reset, .eh_target_reset_handler = tcm_loop_target_reset, - .can_queue = 1024, .this_id = -1, .sg_tablesize = 256, - .cmd_per_lun = 1024, .max_sectors = 0xFFFF, .dma_boundary = PAGE_SIZE - 1, .module = THIS_MODULE, @@ -342,6 +349,9 @@ static int tcm_loop_driver_probe(struct device *dev) sh->max_lun = 0; sh->max_channel = 0; sh->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE; + sh->nr_hw_queues = tcm_loop_nr_hw_queues; + sh->can_queue = tcm_loop_can_queue; + sh->cmd_per_lun = tcm_loop_cmd_per_lun; host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION | diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 405d82d44717..7787c527aad3 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -65,6 +65,16 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd) atomic_long_add(se_cmd->data_length, &deve->read_bytes); + if ((se_cmd->data_direction == DMA_TO_DEVICE) && + deve->lun_access_ro) { + pr_err("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN" + " Access for 0x%08llx\n", + se_cmd->se_tfo->fabric_name, + se_cmd->orig_fe_lun); + rcu_read_unlock(); + return TCM_WRITE_PROTECTED; + } + se_lun = rcu_dereference(deve->se_lun); if (!percpu_ref_tryget_live(&se_lun->lun_ref)) { @@ -76,17 +86,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd) se_cmd->pr_res_key = deve->pr_res_key; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; se_cmd->lun_ref_active = true; - - if ((se_cmd->data_direction == DMA_TO_DEVICE) && - deve->lun_access_ro) { - pr_err("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN" - " Access for 0x%08llx\n", - se_cmd->se_tfo->fabric_name, - se_cmd->orig_fe_lun); - rcu_read_unlock(); - ret = TCM_WRITE_PROTECTED; - goto ref_dev; - } } out_unlock: rcu_read_unlock(); @@ -106,21 +105,20 @@ out_unlock: return TCM_NON_EXISTENT_LUN; } - se_lun = se_sess->se_tpg->tpg_virt_lun0; - se_cmd->se_lun = se_sess->se_tpg->tpg_virt_lun0; - se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; - - percpu_ref_get(&se_lun->lun_ref); - se_cmd->lun_ref_active = true; - /* * Force WRITE PROTECT for virtual LUN 0 */ if ((se_cmd->data_direction != DMA_FROM_DEVICE) && - (se_cmd->data_direction != DMA_NONE)) { - ret = TCM_WRITE_PROTECTED; - goto ref_dev; - } + (se_cmd->data_direction != DMA_NONE)) + return TCM_WRITE_PROTECTED; + + se_lun = se_sess->se_tpg->tpg_virt_lun0; + if (!percpu_ref_tryget_live(&se_lun->lun_ref)) + return TCM_NON_EXISTENT_LUN; + + se_cmd->se_lun = se_sess->se_tpg->tpg_virt_lun0; + se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; + se_cmd->lun_ref_active = true; } /* * RCU reference protected by percpu se_lun->lun_ref taken above that @@ -128,7 +126,6 @@ out_unlock: * pointer can be kfree_rcu() by the final se_lun->lun_group put via * target_core_fabric_configfs.c:target_fabric_port_release */ -ref_dev: se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev); atomic_long_inc(&se_cmd->se_dev->num_cmds); @@ -724,11 +721,24 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) { struct se_device *dev; struct se_lun *xcopy_lun; + int i; dev = hba->backend->ops->alloc_device(hba, name); if (!dev) return NULL; + dev->queues = kcalloc(nr_cpu_ids, sizeof(*dev->queues), GFP_KERNEL); + if (!dev->queues) { + dev->transport->free_device(dev); + return NULL; + } + + dev->queue_cnt = nr_cpu_ids; + for (i = 0; i < dev->queue_cnt; i++) { + INIT_LIST_HEAD(&dev->queues[i].state_list); + spin_lock_init(&dev->queues[i].lock); + } + dev->se_hba = hba; dev->transport = hba->backend->ops; dev->transport_flags = dev->transport->transport_flags_default; @@ -738,9 +748,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) INIT_LIST_HEAD(&dev->dev_sep_list); INIT_LIST_HEAD(&dev->dev_tmr_list); INIT_LIST_HEAD(&dev->delayed_cmd_list); - INIT_LIST_HEAD(&dev->state_list); INIT_LIST_HEAD(&dev->qf_cmd_list); - spin_lock_init(&dev->execute_task_lock); spin_lock_init(&dev->delayed_cmd_lock); spin_lock_init(&dev->dev_reservation_lock); spin_lock_init(&dev->se_port_lock); @@ -1013,6 +1021,7 @@ void target_free_device(struct se_device *dev) if (dev->transport->free_prot) dev->transport->free_prot(dev); + kfree(dev->queues); dev->transport->free_device(dev); } diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index f2bd2e207e0b..8ed93fd205c7 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -211,6 +211,7 @@ static unsigned long long iblock_emulate_read_cap_with_block_size( break; case 512: blocks_long <<= 3; + break; default: break; } diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 5f79ea05f9b8..14db5e568f22 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -337,6 +337,7 @@ static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type, switch (pr_reg_type) { case PR_TYPE_WRITE_EXCLUSIVE: we = 1; + fallthrough; case PR_TYPE_EXCLUSIVE_ACCESS: /* * Some commands are only allowed for the persistent reservation diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 6e8b8d30938f..f7c527a826fd 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -434,20 +434,81 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, return ret; } +/* + * compare @cmp_len bytes of @read_sgl with @cmp_sgl. On miscompare, fill + * @miscmp_off and return TCM_MISCOMPARE_VERIFY. + */ +static sense_reason_t +compare_and_write_do_cmp(struct scatterlist *read_sgl, unsigned int read_nents, + struct scatterlist *cmp_sgl, unsigned int cmp_nents, + unsigned int cmp_len, unsigned int *miscmp_off) +{ + unsigned char *buf = NULL; + struct scatterlist *sg; + sense_reason_t ret; + unsigned int offset; + size_t rc; + int i; + + buf = kzalloc(cmp_len, GFP_KERNEL); + if (!buf) { + ret = TCM_OUT_OF_RESOURCES; + goto out; + } + + rc = sg_copy_to_buffer(cmp_sgl, cmp_nents, buf, cmp_len); + if (!rc) { + pr_err("sg_copy_to_buffer() failed for compare_and_write\n"); + ret = TCM_OUT_OF_RESOURCES; + goto out; + } + /* + * Compare SCSI READ payload against verify payload + */ + offset = 0; + ret = TCM_NO_SENSE; + for_each_sg(read_sgl, sg, read_nents, i) { + unsigned int len = min(sg->length, cmp_len); + unsigned char *addr = kmap_atomic(sg_page(sg)); + + if (memcmp(addr, buf + offset, len)) { + unsigned int i; + + for (i = 0; i < len && addr[i] == buf[offset + i]; i++) + ; + *miscmp_off = offset + i; + pr_warn("Detected MISCOMPARE at offset %u\n", + *miscmp_off); + ret = TCM_MISCOMPARE_VERIFY; + } + kunmap_atomic(addr); + if (ret != TCM_NO_SENSE) + goto out; + + offset += len; + cmp_len -= len; + if (!cmp_len) + break; + } + pr_debug("COMPARE AND WRITE read data matches compare data\n"); +out: + kfree(buf); + return ret; +} + static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success, int *post_ret) { struct se_device *dev = cmd->se_dev; struct sg_table write_tbl = { }; - struct scatterlist *write_sg, *sg; - unsigned char *buf = NULL, *addr; + struct scatterlist *write_sg; struct sg_mapping_iter m; - unsigned int offset = 0, len; - unsigned int nlbas = cmd->t_task_nolb; + unsigned int len; unsigned int block_size = dev->dev_attrib.block_size; - unsigned int compare_len = (nlbas * block_size); + unsigned int compare_len = (cmd->t_task_nolb * block_size); + unsigned int miscmp_off = 0; sense_reason_t ret = TCM_NO_SENSE; - int rc, i; + int i; /* * Handle early failure in transport_generic_request_failure(), @@ -473,12 +534,23 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes goto out; } - buf = kzalloc(cmd->data_length, GFP_KERNEL); - if (!buf) { - pr_err("Unable to allocate compare_and_write buf\n"); - ret = TCM_OUT_OF_RESOURCES; + ret = compare_and_write_do_cmp(cmd->t_bidi_data_sg, + cmd->t_bidi_data_nents, + cmd->t_data_sg, + cmd->t_data_nents, + compare_len, + &miscmp_off); + if (ret == TCM_MISCOMPARE_VERIFY) { + /* + * SBC-4 r15: 5.3 COMPARE AND WRITE command + * In the sense data (see 4.18 and SPC-5) the offset from the + * start of the Data-Out Buffer to the first byte of data that + * was not equal shall be reported in the INFORMATION field. + */ + cmd->sense_info = miscmp_off; + goto out; + } else if (ret) goto out; - } if (sg_alloc_table(&write_tbl, cmd->t_data_nents, GFP_KERNEL) < 0) { pr_err("Unable to allocate compare_and_write sg\n"); @@ -486,44 +558,9 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes goto out; } write_sg = write_tbl.sgl; - /* - * Setup verify and write data payloads from total NumberLBAs. - */ - rc = sg_copy_to_buffer(cmd->t_data_sg, cmd->t_data_nents, buf, - cmd->data_length); - if (!rc) { - pr_err("sg_copy_to_buffer() failed for compare_and_write\n"); - ret = TCM_OUT_OF_RESOURCES; - goto out; - } - /* - * Compare against SCSI READ payload against verify payload - */ - for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, i) { - addr = (unsigned char *)kmap_atomic(sg_page(sg)); - if (!addr) { - ret = TCM_OUT_OF_RESOURCES; - goto out; - } - - len = min(sg->length, compare_len); - - if (memcmp(addr, buf + offset, len)) { - pr_warn("Detected MISCOMPARE for addr: %p buf: %p\n", - addr, buf + offset); - kunmap_atomic(addr); - goto miscompare; - } - kunmap_atomic(addr); - - offset += len; - compare_len -= len; - if (!compare_len) - break; - } i = 0; - len = cmd->t_task_nolb * block_size; + len = compare_len; sg_miter_start(&m, cmd->t_data_sg, cmd->t_data_nents, SG_MITER_TO_SG); /* * Currently assumes NoLB=1 and SGLs are PAGE_SIZE.. @@ -568,13 +605,8 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes __target_execute_cmd(cmd, false); - kfree(buf); return ret; -miscompare: - pr_warn("Target/%s: Send MISCOMPARE check condition and sense\n", - dev->transport->name); - ret = TCM_MISCOMPARE_VERIFY; out: /* * In the MISCOMPARE or failure case, unlock ->caw_sem obtained in @@ -582,7 +614,6 @@ out: */ up(&dev->caw_sem); sg_free_table(&write_tbl); - kfree(buf); return ret; } @@ -1439,7 +1470,7 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, if (rc) { kunmap_atomic(daddr - dsg->offset); kunmap_atomic(paddr - psg->offset); - cmd->bad_sector = sector; + cmd->sense_info = sector; return rc; } next: diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index e4513ef09159..7347285471fa 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -121,57 +121,61 @@ void core_tmr_abort_task( unsigned long flags; bool rc; u64 ref_tag; - - spin_lock_irqsave(&dev->execute_task_lock, flags); - list_for_each_entry_safe(se_cmd, next, &dev->state_list, state_list) { - - if (se_sess != se_cmd->se_sess) - continue; - - /* skip task management functions, including tmr->task_cmd */ - if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) - continue; - - ref_tag = se_cmd->tag; - if (tmr->ref_task_tag != ref_tag) - continue; - - printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", - se_cmd->se_tfo->fabric_name, ref_tag); - - spin_lock(&se_sess->sess_cmd_lock); - rc = __target_check_io_state(se_cmd, se_sess, 0); - spin_unlock(&se_sess->sess_cmd_lock); - if (!rc) - continue; - - list_move_tail(&se_cmd->state_list, &aborted_list); - se_cmd->state_active = false; - - spin_unlock_irqrestore(&dev->execute_task_lock, flags); - - /* - * Ensure that this ABORT request is visible to the LU RESET - * code. - */ - if (!tmr->tmr_dev) - WARN_ON_ONCE(transport_lookup_tmr_lun(tmr->task_cmd) < - 0); - - if (dev->transport->tmr_notify) - dev->transport->tmr_notify(dev, TMR_ABORT_TASK, - &aborted_list); - - list_del_init(&se_cmd->state_list); - target_put_cmd_and_wait(se_cmd); - - printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" - " ref_tag: %llu\n", ref_tag); - tmr->response = TMR_FUNCTION_COMPLETE; - atomic_long_inc(&dev->aborts_complete); - return; + int i; + + for (i = 0; i < dev->queue_cnt; i++) { + spin_lock_irqsave(&dev->queues[i].lock, flags); + list_for_each_entry_safe(se_cmd, next, &dev->queues[i].state_list, + state_list) { + if (se_sess != se_cmd->se_sess) + continue; + + /* + * skip task management functions, including + * tmr->task_cmd + */ + if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) + continue; + + ref_tag = se_cmd->tag; + if (tmr->ref_task_tag != ref_tag) + continue; + + pr_err("ABORT_TASK: Found referenced %s task_tag: %llu\n", + se_cmd->se_tfo->fabric_name, ref_tag); + + spin_lock(&se_sess->sess_cmd_lock); + rc = __target_check_io_state(se_cmd, se_sess, 0); + spin_unlock(&se_sess->sess_cmd_lock); + if (!rc) + continue; + + list_move_tail(&se_cmd->state_list, &aborted_list); + se_cmd->state_active = false; + spin_unlock_irqrestore(&dev->queues[i].lock, flags); + + /* + * Ensure that this ABORT request is visible to the LU + * RESET code. + */ + if (!tmr->tmr_dev) + WARN_ON_ONCE(transport_lookup_tmr_lun(tmr->task_cmd) < 0); + + if (dev->transport->tmr_notify) + dev->transport->tmr_notify(dev, TMR_ABORT_TASK, + &aborted_list); + + list_del_init(&se_cmd->state_list); + target_put_cmd_and_wait(se_cmd); + + pr_err("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for ref_tag: %llu\n", + ref_tag); + tmr->response = TMR_FUNCTION_COMPLETE; + atomic_long_inc(&dev->aborts_complete); + return; + } + spin_unlock_irqrestore(&dev->queues[i].lock, flags); } - spin_unlock_irqrestore(&dev->execute_task_lock, flags); if (dev->transport->tmr_notify) dev->transport->tmr_notify(dev, TMR_ABORT_TASK, &aborted_list); @@ -273,7 +277,7 @@ static void core_tmr_drain_state_list( struct se_session *sess; struct se_cmd *cmd, *next; unsigned long flags; - int rc; + int rc, i; /* * Complete outstanding commands with TASK_ABORTED SAM status. @@ -297,35 +301,39 @@ static void core_tmr_drain_state_list( * Note that this seems to be independent of TAS (Task Aborted Status) * in the Control Mode Page. */ - spin_lock_irqsave(&dev->execute_task_lock, flags); - list_for_each_entry_safe(cmd, next, &dev->state_list, state_list) { - /* - * For PREEMPT_AND_ABORT usage, only process commands - * with a matching reservation key. - */ - if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd)) - continue; - - /* - * Not aborting PROUT PREEMPT_AND_ABORT CDB.. - */ - if (prout_cmd == cmd) - continue; - - sess = cmd->se_sess; - if (WARN_ON_ONCE(!sess)) - continue; - - spin_lock(&sess->sess_cmd_lock); - rc = __target_check_io_state(cmd, tmr_sess, tas); - spin_unlock(&sess->sess_cmd_lock); - if (!rc) - continue; - - list_move_tail(&cmd->state_list, &drain_task_list); - cmd->state_active = false; + for (i = 0; i < dev->queue_cnt; i++) { + spin_lock_irqsave(&dev->queues[i].lock, flags); + list_for_each_entry_safe(cmd, next, &dev->queues[i].state_list, + state_list) { + /* + * For PREEMPT_AND_ABORT usage, only process commands + * with a matching reservation key. + */ + if (target_check_cdb_and_preempt(preempt_and_abort_list, + cmd)) + continue; + + /* + * Not aborting PROUT PREEMPT_AND_ABORT CDB.. + */ + if (prout_cmd == cmd) + continue; + + sess = cmd->se_sess; + if (WARN_ON_ONCE(!sess)) + continue; + + spin_lock(&sess->sess_cmd_lock); + rc = __target_check_io_state(cmd, tmr_sess, tas); + spin_unlock(&sess->sess_cmd_lock); + if (!rc) + continue; + + list_move_tail(&cmd->state_list, &drain_task_list); + cmd->state_active = false; + } + spin_unlock_irqrestore(&dev->queues[i].lock, flags); } - spin_unlock_irqrestore(&dev->execute_task_lock, flags); if (dev->transport->tmr_notify) dev->transport->tmr_notify(dev, preempt_and_abort_list ? diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 62aa5fa63ac0..736847c933e5 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -328,7 +328,7 @@ static void target_shutdown_sessions(struct se_node_acl *acl) restart: spin_lock_irqsave(&acl->nacl_sess_lock, flags); list_for_each_entry(sess, &acl->acl_sess_list, sess_acl_list) { - if (sess->sess_tearing_down) + if (atomic_read(&sess->stopped)) continue; list_del_init(&sess->sess_acl_list); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ff26ab0a5f60..fca4bd079d02 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -215,7 +215,7 @@ static void target_release_sess_cmd_refcnt(struct percpu_ref *ref) { struct se_session *sess = container_of(ref, typeof(*sess), cmd_count); - wake_up(&sess->cmd_list_wq); + wake_up(&sess->cmd_count_wq); } /** @@ -228,9 +228,10 @@ int transport_init_session(struct se_session *se_sess) { INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); - INIT_LIST_HEAD(&se_sess->sess_cmd_list); spin_lock_init(&se_sess->sess_cmd_lock); - init_waitqueue_head(&se_sess->cmd_list_wq); + init_waitqueue_head(&se_sess->cmd_count_wq); + init_completion(&se_sess->stop_done); + atomic_set(&se_sess->stopped, 0); return percpu_ref_init(&se_sess->cmd_count, target_release_sess_cmd_refcnt, 0, GFP_KERNEL); } @@ -238,6 +239,14 @@ EXPORT_SYMBOL(transport_init_session); void transport_uninit_session(struct se_session *se_sess) { + /* + * Drivers like iscsi and loop do not call target_stop_session + * during session shutdown so we have to drop the ref taken at init + * time here. + */ + if (!atomic_read(&se_sess->stopped)) + percpu_ref_put(&se_sess->cmd_count); + percpu_ref_exit(&se_sess->cmd_count); } @@ -650,12 +659,12 @@ static void target_remove_from_state_list(struct se_cmd *cmd) if (!dev) return; - spin_lock_irqsave(&dev->execute_task_lock, flags); + spin_lock_irqsave(&dev->queues[cmd->cpuid].lock, flags); if (cmd->state_active) { list_del(&cmd->state_list); cmd->state_active = false; } - spin_unlock_irqrestore(&dev->execute_task_lock, flags); + spin_unlock_irqrestore(&dev->queues[cmd->cpuid].lock, flags); } /* @@ -866,10 +875,7 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) INIT_WORK(&cmd->work, success ? target_complete_ok_work : target_complete_failure_work); - if (cmd->se_cmd_flags & SCF_USE_CPUID) - queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work); - else - queue_work(target_completion_wq, &cmd->work); + queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work); } EXPORT_SYMBOL(target_complete_cmd); @@ -897,12 +903,13 @@ static void target_add_to_state_list(struct se_cmd *cmd) struct se_device *dev = cmd->se_dev; unsigned long flags; - spin_lock_irqsave(&dev->execute_task_lock, flags); + spin_lock_irqsave(&dev->queues[cmd->cpuid].lock, flags); if (!cmd->state_active) { - list_add_tail(&cmd->state_list, &dev->state_list); + list_add_tail(&cmd->state_list, + &dev->queues[cmd->cpuid].state_list); cmd->state_active = true; } - spin_unlock_irqrestore(&dev->execute_task_lock, flags); + spin_unlock_irqrestore(&dev->queues[cmd->cpuid].lock, flags); } /* @@ -1390,6 +1397,9 @@ void transport_init_se_cmd( cmd->sense_buffer = sense_buffer; cmd->orig_fe_lun = unpacked_lun; + if (!(cmd->se_cmd_flags & SCF_USE_CPUID)) + cmd->cpuid = smp_processor_id(); + cmd->state_active = false; } EXPORT_SYMBOL(transport_init_se_cmd); @@ -1607,6 +1617,9 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess BUG_ON(!se_tpg); BUG_ON(se_cmd->se_tfo || se_cmd->se_sess); BUG_ON(in_interrupt()); + + if (flags & TARGET_SCF_USE_CPUID) + se_cmd->se_cmd_flags |= SCF_USE_CPUID; /* * Initialize se_cmd for target operation. From this point * exceptions are handled by sending exception status via @@ -1616,17 +1629,11 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess data_length, data_dir, task_attr, sense, unpacked_lun); - if (flags & TARGET_SCF_USE_CPUID) - se_cmd->se_cmd_flags |= SCF_USE_CPUID; - else - se_cmd->cpuid = WORK_CPU_UNBOUND; - if (flags & TARGET_SCF_UNKNOWN_SIZE) se_cmd->unknown_data_length = 1; /* - * Obtain struct se_cmd->cmd_kref reference and add new cmd to - * se_sess->sess_cmd_list. A second kref_get here is necessary - * for fabrics using TARGET_SCF_ACK_KREF that expect a second + * Obtain struct se_cmd->cmd_kref reference. A second kref_get here is + * necessary for fabrics using TARGET_SCF_ACK_KREF that expect a second * kref_put() to happen during fabric packet acknowledgement. */ ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF); @@ -1764,29 +1771,6 @@ static void target_complete_tmr_failure(struct work_struct *work) transport_cmd_check_stop_to_fabric(se_cmd); } -static bool target_lookup_lun_from_tag(struct se_session *se_sess, u64 tag, - u64 *unpacked_lun) -{ - struct se_cmd *se_cmd; - unsigned long flags; - bool ret = false; - - spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) { - if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) - continue; - - if (se_cmd->tag == tag) { - *unpacked_lun = se_cmd->orig_fe_lun; - ret = true; - break; - } - } - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); - - return ret; -} - /** * target_submit_tmr - lookup unpacked lun and submit uninitialized se_cmd * for TMR CDBs @@ -1834,16 +1818,6 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, core_tmr_release_req(se_cmd->se_tmr_req); return ret; } - /* - * If this is ABORT_TASK with no explicit fabric provided LUN, - * go ahead and search active session tags for a match to figure - * out unpacked_lun for the original se_cmd. - */ - if (tm_type == TMR_ABORT_TASK && (flags & TARGET_SCF_LOOKUP_LUN_FROM_TAG)) { - if (!target_lookup_lun_from_tag(se_sess, tag, - &se_cmd->orig_fe_lun)) - goto failure; - } ret = transport_lookup_tmr_lun(se_cmd); if (ret) @@ -2788,14 +2762,13 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) EXPORT_SYMBOL(transport_generic_free_cmd); /** - * target_get_sess_cmd - Add command to active ->sess_cmd_list + * target_get_sess_cmd - Verify the session is accepting cmds and take ref * @se_cmd: command descriptor to add * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) { struct se_session *se_sess = se_cmd->se_sess; - unsigned long flags; int ret = 0; /* @@ -2810,15 +2783,8 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) se_cmd->se_cmd_flags |= SCF_ACK_KREF; } - spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - if (se_sess->sess_tearing_down) { + if (!percpu_ref_tryget_live(&se_sess->cmd_count)) ret = -ESHUTDOWN; - goto out; - } - list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); - percpu_ref_get(&se_sess->cmd_count); -out: - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); if (ret && ack_kref) target_put_sess_cmd(se_cmd); @@ -2843,13 +2809,6 @@ static void target_release_cmd_kref(struct kref *kref) struct se_session *se_sess = se_cmd->se_sess; struct completion *free_compl = se_cmd->free_compl; struct completion *abrt_compl = se_cmd->abrt_compl; - unsigned long flags; - - if (se_sess) { - spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - list_del_init(&se_cmd->se_cmd_list); - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); - } target_free_cmd_mem(se_cmd); se_cmd->se_tfo->release_cmd(se_cmd); @@ -2977,21 +2936,25 @@ void target_show_cmd(const char *pfx, struct se_cmd *cmd) } EXPORT_SYMBOL(target_show_cmd); +static void target_stop_session_confirm(struct percpu_ref *ref) +{ + struct se_session *se_sess = container_of(ref, struct se_session, + cmd_count); + complete_all(&se_sess->stop_done); +} + /** - * target_sess_cmd_list_set_waiting - Set sess_tearing_down so no new commands are queued. - * @se_sess: session to flag + * target_stop_session - Stop new IO from being queued on the session. + * @se_sess: session to stop */ -void target_sess_cmd_list_set_waiting(struct se_session *se_sess) +void target_stop_session(struct se_session *se_sess) { - unsigned long flags; - - spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - se_sess->sess_tearing_down = 1; - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); - - percpu_ref_kill(&se_sess->cmd_count); + pr_debug("Stopping session queue.\n"); + if (atomic_cmpxchg(&se_sess->stopped, 0, 1) == 0) + percpu_ref_kill_and_confirm(&se_sess->cmd_count, + target_stop_session_confirm); } -EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); +EXPORT_SYMBOL(target_stop_session); /** * target_wait_for_sess_cmds - Wait for outstanding commands @@ -2999,19 +2962,19 @@ EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); */ void target_wait_for_sess_cmds(struct se_session *se_sess) { - struct se_cmd *cmd; int ret; - WARN_ON_ONCE(!se_sess->sess_tearing_down); + WARN_ON_ONCE(!atomic_read(&se_sess->stopped)); do { - ret = wait_event_timeout(se_sess->cmd_list_wq, + pr_debug("Waiting for running cmds to complete.\n"); + ret = wait_event_timeout(se_sess->cmd_count_wq, percpu_ref_is_zero(&se_sess->cmd_count), 180 * HZ); - list_for_each_entry(cmd, &se_sess->sess_cmd_list, se_cmd_list) - target_show_cmd("session shutdown: still waiting for ", - cmd); } while (ret <= 0); + + wait_for_completion(&se_sess->stop_done); + pr_debug("Waiting for cmds done.\n"); } EXPORT_SYMBOL(target_wait_for_sess_cmds); @@ -3094,14 +3057,14 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) } EXPORT_SYMBOL(transport_wait_for_tasks); -struct sense_info { +struct sense_detail { u8 key; u8 asc; u8 ascq; - bool add_sector_info; + bool add_sense_info; }; -static const struct sense_info sense_info_table[] = { +static const struct sense_detail sense_detail_table[] = { [TCM_NO_SENSE] = { .key = NOT_READY }, @@ -3196,24 +3159,25 @@ static const struct sense_info sense_info_table[] = { .key = MISCOMPARE, .asc = 0x1d, /* MISCOMPARE DURING VERIFY OPERATION */ .ascq = 0x00, + .add_sense_info = true, }, [TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED] = { .key = ABORTED_COMMAND, .asc = 0x10, .ascq = 0x01, /* LOGICAL BLOCK GUARD CHECK FAILED */ - .add_sector_info = true, + .add_sense_info = true, }, [TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED] = { .key = ABORTED_COMMAND, .asc = 0x10, .ascq = 0x02, /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */ - .add_sector_info = true, + .add_sense_info = true, }, [TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED] = { .key = ABORTED_COMMAND, .asc = 0x10, .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ - .add_sector_info = true, + .add_sense_info = true, }, [TCM_COPY_TARGET_DEVICE_NOT_REACHABLE] = { .key = COPY_ABORTED, @@ -3261,42 +3225,42 @@ static const struct sense_info sense_info_table[] = { */ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) { - const struct sense_info *si; + const struct sense_detail *sd; u8 *buffer = cmd->sense_buffer; int r = (__force int)reason; u8 key, asc, ascq; bool desc_format = target_sense_desc_format(cmd->se_dev); - if (r < ARRAY_SIZE(sense_info_table) && sense_info_table[r].key) - si = &sense_info_table[r]; + if (r < ARRAY_SIZE(sense_detail_table) && sense_detail_table[r].key) + sd = &sense_detail_table[r]; else - si = &sense_info_table[(__force int) + sd = &sense_detail_table[(__force int) TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE]; - key = si->key; + key = sd->key; if (reason == TCM_CHECK_CONDITION_UNIT_ATTENTION) { if (!core_scsi3_ua_for_check_condition(cmd, &key, &asc, &ascq)) { cmd->scsi_status = SAM_STAT_BUSY; return; } - } else if (si->asc == 0) { + } else if (sd->asc == 0) { WARN_ON_ONCE(cmd->scsi_asc == 0); asc = cmd->scsi_asc; ascq = cmd->scsi_ascq; } else { - asc = si->asc; - ascq = si->ascq; + asc = sd->asc; + ascq = sd->ascq; } cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; cmd->scsi_status = SAM_STAT_CHECK_CONDITION; cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; scsi_build_sense_buffer(desc_format, buffer, key, asc, ascq); - if (si->add_sector_info) + if (sd->add_sense_info) WARN_ON_ONCE(scsi_set_sense_information(buffer, cmd->scsi_sense_length, - cmd->bad_sector) < 0); + cmd->sense_info) < 0); } int diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 590e6d072228..6b171fff007b 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -586,14 +586,15 @@ static inline void tcmu_cmd_set_block_cnts(struct tcmu_cmd *cmd) } static int new_block_to_iov(struct tcmu_dev *udev, struct tcmu_cmd *cmd, - struct iovec **iov, int prev_dbi, int *remain) + struct iovec **iov, int prev_dbi, int len) { /* Get the next dbi */ int dbi = tcmu_cmd_get_dbi(cmd); + /* Do not add more than DATA_BLOCK_SIZE to iov */ - int len = min_t(int, DATA_BLOCK_SIZE, *remain); + if (len > DATA_BLOCK_SIZE) + len = DATA_BLOCK_SIZE; - *remain -= len; /* * The following code will gather and map the blocks to the same iovec * when the blocks are all next to each other. @@ -618,8 +619,8 @@ static void tcmu_setup_iovs(struct tcmu_dev *udev, struct tcmu_cmd *cmd, int dbi = -2; /* We prepare the IOVs for DMA_FROM_DEVICE transfer direction */ - while (data_length > 0) - dbi = new_block_to_iov(udev, cmd, iov, dbi, &data_length); + for (; data_length > 0; data_length -= DATA_BLOCK_SIZE) + dbi = new_block_to_iov(udev, cmd, iov, dbi, data_length); } static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd) @@ -688,67 +689,83 @@ static inline size_t head_to_end(size_t head, size_t size) #define UPDATE_HEAD(head, used, size) smp_store_release(&head, ((head % size) + used) % size) -static void scatter_data_area(struct tcmu_dev *udev, struct tcmu_cmd *tcmu_cmd, - struct iovec **iov) +#define TCMU_SG_TO_DATA_AREA 1 +#define TCMU_DATA_AREA_TO_SG 2 + +static inline void tcmu_copy_data(struct tcmu_dev *udev, + struct tcmu_cmd *tcmu_cmd, uint32_t direction, + struct scatterlist *sg, unsigned int sg_nents, + struct iovec **iov, size_t data_len) { - struct se_cmd *se_cmd = tcmu_cmd->se_cmd; /* start value of dbi + 1 must not be a valid dbi */ - int i, dbi = -2; - int block_remaining = 0; - int data_len = se_cmd->data_length; - void *from, *to = NULL; - size_t copy_bytes, offset; - struct scatterlist *sg; - struct page *page = NULL; - - for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, i) { - int sg_remaining = sg->length; - from = kmap_atomic(sg_page(sg)) + sg->offset; - while (sg_remaining > 0) { - if (block_remaining == 0) { - if (to) { - flush_dcache_page(page); - kunmap_atomic(to); - } - - /* get next dbi and add to IOVs */ - dbi = new_block_to_iov(udev, tcmu_cmd, iov, dbi, - &data_len); - page = tcmu_get_block_page(udev, dbi); - to = kmap_atomic(page); - block_remaining = DATA_BLOCK_SIZE; - } + int dbi = -2; + size_t block_remaining, cp_len; + struct sg_mapping_iter sg_iter; + unsigned int sg_flags; + struct page *page; + void *data_page_start, *data_addr; - copy_bytes = min_t(size_t, sg_remaining, - block_remaining); - offset = DATA_BLOCK_SIZE - block_remaining; - memcpy(to + offset, from + sg->length - sg_remaining, - copy_bytes); + if (direction == TCMU_SG_TO_DATA_AREA) + sg_flags = SG_MITER_ATOMIC | SG_MITER_FROM_SG; + else + sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG; + sg_miter_start(&sg_iter, sg, sg_nents, sg_flags); - sg_remaining -= copy_bytes; - block_remaining -= copy_bytes; + while (data_len) { + if (direction == TCMU_SG_TO_DATA_AREA) + dbi = new_block_to_iov(udev, tcmu_cmd, iov, dbi, + data_len); + else + dbi = tcmu_cmd_get_dbi(tcmu_cmd); + page = tcmu_get_block_page(udev, dbi); + if (direction == TCMU_DATA_AREA_TO_SG) + flush_dcache_page(page); + data_page_start = kmap_atomic(page); + block_remaining = DATA_BLOCK_SIZE; + + while (block_remaining && data_len) { + if (!sg_miter_next(&sg_iter)) { + /* set length to 0 to abort outer loop */ + data_len = 0; + pr_debug("tcmu_move_data: aborting data copy due to exhausted sg_list\n"); + break; + } + cp_len = min3(sg_iter.length, block_remaining, data_len); + + data_addr = data_page_start + + DATA_BLOCK_SIZE - block_remaining; + if (direction == TCMU_SG_TO_DATA_AREA) + memcpy(data_addr, sg_iter.addr, cp_len); + else + memcpy(sg_iter.addr, data_addr, cp_len); + + data_len -= cp_len; + block_remaining -= cp_len; + sg_iter.consumed = cp_len; } - kunmap_atomic(from - sg->offset); - } + sg_miter_stop(&sg_iter); - if (to) { - flush_dcache_page(page); - kunmap_atomic(to); + kunmap_atomic(data_page_start); + if (direction == TCMU_SG_TO_DATA_AREA) + flush_dcache_page(page); } } -static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd, +static void scatter_data_area(struct tcmu_dev *udev, struct tcmu_cmd *tcmu_cmd, + struct iovec **iov) +{ + struct se_cmd *se_cmd = tcmu_cmd->se_cmd; + + tcmu_copy_data(udev, tcmu_cmd, TCMU_SG_TO_DATA_AREA, se_cmd->t_data_sg, + se_cmd->t_data_nents, iov, se_cmd->data_length); +} + +static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *tcmu_cmd, bool bidi, uint32_t read_len) { - struct se_cmd *se_cmd = cmd->se_cmd; - int i, dbi; - int block_remaining = 0; - void *from = NULL, *to; - size_t copy_bytes, offset; - struct scatterlist *sg, *data_sg; - struct page *page; + struct se_cmd *se_cmd = tcmu_cmd->se_cmd; + struct scatterlist *data_sg; unsigned int data_nents; - uint32_t count = 0; if (!bidi) { data_sg = se_cmd->t_data_sg; @@ -759,46 +776,15 @@ static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd, * buffer blocks, and before gathering the Data-In buffer * the Data-Out buffer blocks should be skipped. */ - count = cmd->dbi_cnt - cmd->dbi_bidi_cnt; + tcmu_cmd_set_dbi_cur(tcmu_cmd, + tcmu_cmd->dbi_cnt - tcmu_cmd->dbi_bidi_cnt); data_sg = se_cmd->t_bidi_data_sg; data_nents = se_cmd->t_bidi_data_nents; } - tcmu_cmd_set_dbi_cur(cmd, count); - - for_each_sg(data_sg, sg, data_nents, i) { - int sg_remaining = sg->length; - to = kmap_atomic(sg_page(sg)) + sg->offset; - while (sg_remaining > 0 && read_len > 0) { - if (block_remaining == 0) { - if (from) - kunmap_atomic(from); - - block_remaining = DATA_BLOCK_SIZE; - dbi = tcmu_cmd_get_dbi(cmd); - page = tcmu_get_block_page(udev, dbi); - from = kmap_atomic(page); - flush_dcache_page(page); - } - copy_bytes = min_t(size_t, sg_remaining, - block_remaining); - if (read_len < copy_bytes) - copy_bytes = read_len; - offset = DATA_BLOCK_SIZE - block_remaining; - memcpy(to + sg->length - sg_remaining, from + offset, - copy_bytes); - - sg_remaining -= copy_bytes; - block_remaining -= copy_bytes; - read_len -= copy_bytes; - } - kunmap_atomic(to - sg->offset); - if (read_len == 0) - break; - } - if (from) - kunmap_atomic(from); + tcmu_copy_data(udev, tcmu_cmd, TCMU_DATA_AREA_TO_SG, data_sg, + data_nents, NULL, read_len); } static inline size_t spc_bitmap_free(unsigned long *bitmap, uint32_t thresh) diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index a7ed56602c6c..768f250680d9 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -19,7 +19,6 @@ #include <asm/unaligned.h> #include <scsi/scsi_tcq.h> #include <scsi/libfc.h> -#include <scsi/fc_encode.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> @@ -551,7 +550,7 @@ static void ft_send_work(struct work_struct *work) if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), ntohl(fcp->fc_dl), task_attr, data_dir, - TARGET_SCF_ACK_KREF | TARGET_SCF_USE_CPUID)) + TARGET_SCF_ACK_KREF)) goto err; pr_debug("r_ctl %x target_submit_cmd %p\n", fh->fh_r_ctl, cmd); diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 6a38ff936389..bbe2e29612fa 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -28,7 +28,6 @@ #include <linux/ratelimit.h> #include <asm/unaligned.h> #include <scsi/libfc.h> -#include <scsi/fc_encode.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 4fd6a1de947c..23ce506d5402 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -275,7 +275,7 @@ static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id) static void ft_close_sess(struct ft_sess *sess) { - target_sess_cmd_list_set_waiting(sess->se_sess); + target_stop_session(sess->se_sess); target_wait_for_sess_cmds(sess->se_sess); ft_sess_put(sess); } |