Re: [PATCH v3 14/23] scsi: hisi_sas: add v3 cq interrupt handler
> + case SAS_PROTOCOL_SSP: > + { > + unsigned char op = task->ssp_task.cmd->cmnd[0]; > + > + if (op == READ_6 || op == WRITE_6 || > + op == READ_10 || op == WRITE_10 || > + op == READ_12 || op == WRITE_12 || > + op == READ_16 || op == WRITE_16) > + return true; > + break; > + } Wee. why do you care? What about 32-byte CDs or things like Write Same?
Re: [PATCH v3 13/23] scsi: hisi_sas: add phy up/down/bcast and channel ISR
On Wed, May 31, 2017 at 10:33:05PM +0800, John Garry wrote: > From: Xiang Chen> > Add code to initialise interrupts and add some interrupt handlers. > > Signed-off-by: John Garry > Signed-off-by: Xiang Chen > --- > drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 281 > + > 1 file changed, 281 insertions(+) > > diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c > b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c > index 9651658..49f14d2 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c > +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c > @@ -173,6 +173,13 @@ enum { > HISI_SAS_PHY_INT_NR > }; > > +static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) > +{ > + void __iomem *regs = hisi_hba->regs + off; > + > + return readl(regs); > +} > + > static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val) > { > void __iomem *regs = hisi_hba->regs + off; > @@ -397,6 +404,276 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, > int phy_no) > hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control); > } > > +static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) > +{ > + int i, res = 0; > + u32 context, port_id, link_rate, hard_phy_linkrate; > + struct hisi_sas_phy *phy = _hba->phy[phy_no]; > + struct asd_sas_phy *sas_phy = >sas_phy; > + struct device *dev = hisi_hba->dev; > + > + hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); > + > + port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA); > + port_id = (port_id >> (4 * phy_no)) & 0xf; > + link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE); > + link_rate = (link_rate >> (phy_no * 4)) & 0xf; > + > + if (port_id == 0xf) { > + dev_err(dev, "phyup: phy%d invalid portid\n", phy_no); > + res = IRQ_NONE; > + goto end; > + } > + sas_phy->linkrate = link_rate; > + hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no, > + HARD_PHY_LINKRATE); > + phy->maximum_linkrate = hard_phy_linkrate & 0xf; > + phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf; > + phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); > + > + /* Check for SATA dev */ > + context = hisi_sas_read32(hisi_hba, PHY_CONTEXT); > + if (context & (1 << phy_no)) { > + struct hisi_sas_initial_fis *initial_fis; > + struct dev_to_host_fis *fis; > + u8 attached_sas_addr[SAS_ADDR_SIZE] = {0}; > + > + dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); > + initial_fis = _hba->initial_fis[phy_no]; > + fis = _fis->fis; > + sas_phy->oob_mode = SATA_OOB_MODE; > + attached_sas_addr[0] = 0x50; > + attached_sas_addr[7] = phy_no; > + memcpy(sas_phy->attached_sas_addr, > +attached_sas_addr, > +SAS_ADDR_SIZE); > + memcpy(sas_phy->frame_rcvd, fis, > +sizeof(struct dev_to_host_fis)); > + phy->phy_type |= PORT_TYPE_SATA; > + phy->identify.device_type = SAS_SATA_DEV; > + phy->frame_rcvd_size = sizeof(struct dev_to_host_fis); > + phy->identify.target_port_protocols = SAS_PROTOCOL_SATA; > + } else { > + u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd; > + struct sas_identify_frame *id = > + (struct sas_identify_frame *)frame_rcvd; > + > + dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); > + for (i = 0; i < 6; i++) { > + u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no, > +RX_IDAF_DWORD0 + (i * 4)); > + frame_rcvd[i] = __swab32(idaf); > + } > + sas_phy->oob_mode = SAS_OOB_MODE; > + memcpy(sas_phy->attached_sas_addr, > +>sas_addr, > +SAS_ADDR_SIZE); > + phy->phy_type |= PORT_TYPE_SAS; > + phy->identify.device_type = id->dev_type; > + phy->frame_rcvd_size = sizeof(struct sas_identify_frame); > + if (phy->identify.device_type == SAS_END_DEVICE) > + phy->identify.target_port_protocols = > + SAS_PROTOCOL_SSP; > + else if (phy->identify.device_type != SAS_PHY_UNUSED) > + phy->identify.target_port_protocols = > + SAS_PROTOCOL_SMP; > + } > + > + phy->port_id = port_id; > + phy->phy_attached = 1; > + queue_work(hisi_hba->wq, >phyup_ws); > + > +end: > + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, > + CHL_INT0_SL_PHY_ENABLE_MSK); > + hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0);
[GIT PULL] target fixes for v4.12-rc4
Hello Linus, Here are the target-pending fixes for v4.12-rc4. Please go ahead and pull from: git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master This includes: - ibmviscsis ABORT_TASK handling fixes that missed the v4.12 merge window. (Bryant Ly and Michael Cyr) - Re-add a target-core check enforcing WRITE overflow reject that was relaxed in v4.3, to avoid unsupported iscsi-target immediate data overflow. (nab) - Fix a target-core-user OOPs during device removal. (MNC + Bryant Ly) - Fix a long standing iscsi-target potential issue where kthread exit did not wait for kthread_should_stop(). (Jiang Yi) - Fix a iscsi-target v3.12.y regression OOPs involving initial login PDU processing during asynchronous TCP connection close. (MNC + nab) This is a little larger than usual for an -rc4, primarily due to the iscsi-target v3.12.y regression OOPs bug-fix. However, it's an important patch as MNC + Hannes where both able to trigger it using a reduced iscsi initiator login timeout combined with a backend taking a long time to complete I/Os during iscsi login driven session reinstatement. Note the trailing two patches have a recent CommitDate, as the second to last was updated today to include MNC's tested-by and reviewed-by tags. The patches themselves has not changed though, and both have been run through manual and automated regression testing from multiple parties over the last 7 days. Thank you, --nab Bryant G. Ly (2): ibmvscsis: Clear left-over abort_cmd pointers ibmvscsis: Fix the incorrect req_lim_delta Jiang Yi (1): iscsi-target: Always wait for kthread_should_stop() before kthread exit Mike Christie (1): tcmu: fix crash during device removal Nicholas Bellinger (2): target: Re-add check to reject control WRITEs with overflow data iscsi-target: Fix initial login PDU asynchronous socket close OOPs drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 27 - drivers/target/iscsi/iscsi_target.c | 30 - drivers/target/iscsi/iscsi_target_erl0.c | 6 +- drivers/target/iscsi/iscsi_target_erl0.h | 2 +- drivers/target/iscsi/iscsi_target_login.c | 4 + drivers/target/iscsi/iscsi_target_nego.c | 194 -- drivers/target/target_core_transport.c| 23 +++- drivers/target/target_core_user.c | 46 +-- include/target/iscsi/iscsi_target_core.h | 1 + 9 files changed, 241 insertions(+), 92 deletions(-)
Re: [PATCH] megaraid: Fix a sleep-in-atomic bug
On 05/31/2017 06:18 PM, Sumit Saxena wrote: -Original Message- From: Jia-Ju Bai [mailto:baijiaju1...@163.com] Sent: Wednesday, May 31, 2017 8:27 AM To: kashyap.de...@broadcom.com; sumit.sax...@broadcom.com; shivasharan.srikanteshw...@broadcom.com; j...@linux.vnet.ibm.com; martin.peter...@oracle.com Cc: megaraidlinux@broadcom.com; linux-scsi@vger.kernel.org; linux- ker...@vger.kernel.org; Jia-Ju Bai Subject: [PATCH] megaraid: Fix a sleep-in-atomic bug The driver may sleep under a spin lock, and the function call path is: mraid_mm_attach_buf (acquire the lock by spin_lock_irqsave) pci_pool_alloc(GFP_KERNEL) --> may sleep To fix it, the "GFP_KERNEL" is replaced with "GFP_ATOMIC". Signed-off-by: Jia-Ju Bai--- drivers/scsi/megaraid/megaraid_mm.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index 4cf9ed9..c43afb8 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -574,7 +574,7 @@ kioc->pool_index = right_pool; kioc->free_buf = 1; - kioc->buf_vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, + kioc->buf_vaddr = pci_pool_alloc(pool->handle, GFP_ATOMIC, >buf_paddr); spin_unlock_irqrestore(>lock, flags); This is very old driver and reached EOL. Did you face any issue because of this bug or discover this through code review? Anyways patch looks good to me. Acked-by: Sumit Saxena -- 1.7.9.5 Hi, This bug is found by a static analysis tool and my code review. Jia-Ju Bai
Re: [PATCH 1/1] scsi: scsi_debug: Avoid PI being disabled when TGPS is enabled
Ewan, > Code is correct. > > s/TGPS/TPGS in the subject line and in one place in the patch > description. Also fixed the original, incorrect comment in the code that begat the patch description typo. Thanks! Applied to 4.12/scsi-fixes. -- Martin K. Petersen Oracle Linux Engineering
Re: [PATCH] scsi: lpfc: fix spelling mistake "entrys" -> "entries"
Colin, > Trivial fix to spelling mistake in debugfs message Applied to 4.13/scsi-queue. Thanks! -- Martin K. Petersen Oracle Linux Engineering
Re: [PATCH] qla2xxx: Fix extraneous ref on sp's after adapter break
Bill, > Hung task timeouts can result if a qlogic board breaks unexpectedly > while running I/O. These tasks become hung because command srb > reference counts are not going to zero, hence the affected srbs and > commands do not get freed. This fix accounts for this extra reference > in the srbs in the case of a board failure. Applied to 4.12/scsi-fixes, thanks! -- Martin K. Petersen Oracle Linux Engineering
Re: [PATCH] scsi: lpfc: Avoid NULL pointer dereference in lpfc_els_abort()
Guilherme, > We might have a NULL pring in lpfc_els_abort(), for example on error > recovery path, since queues are destroyed during error recovery > mechanism. > > In this case, we should just drop the abort since the queues will be > recreated anyway. This patch just verifies for NULL pointer and stop > the abortion of the queue in case of a NULL pring. > > Also, this patch converts return type of lpfc_els_abort() from int to > void, since it's not checked anywhere. Applied to 4.12/scsi-fixes. Thanks! -- Martin K. Petersen Oracle Linux Engineering
Re: [PATCH] scsi: lpfc: prevent potential null pointer dereference
Gustavo A., > Null check at line 966: if (ndlp) {, implies that ndlp might be NULL. > Functions lpfc_nlp_set_state() and lpfc_issue_els_prli() dereference > pointer ndlp. Include these function calls inside the IF block that > tests pointer ndlp. Applied to 4.12/scsi-fixes. Thank you! -- Martin K. Petersen Oracle Linux Engineering
Re: [PATCH] lpfc: nvmet_fc: fix format string
Arnd, > The lpfc_nvmeio_data() tracing helper always takes a format string and > three additional arguments. The latest caller has a format string with > only two integer arguments, causing this harmless warning: Applied to 4.12/scsi-fixes. Thank you! -- Martin K. Petersen Oracle Linux Engineering
Linux kernel 4.9.25: signed integer overflow in drivers/scsi/scsicam.c:173:29
Hello scsi maintainer, I would like to report a signed integer overflow in drivers/scsi/scsicam.c:173:29 reported on the Gentoo bug reporting system. https://bugs.gentoo.org/show_bug.cgi?id=617820 The problem looks present ,at least , in the Linux kernel 4.9.25 regards, Alice Ferrazzi Gentoo kernel project leader signature.asc Description: PGP signature
Re: [PATCH v3 3/9] blk-mq: use the introduced blk_mq_unquiesce_queue()
On Wed, May 31, 2017 at 03:21:41PM +, Bart Van Assche wrote: > On Wed, 2017-05-31 at 20:37 +0800, Ming Lei wrote: > > diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c > > index 99e16ac479e3..ffcf05765e2b 100644 > > --- a/drivers/scsi/scsi_lib.c > > +++ b/drivers/scsi/scsi_lib.c > > @@ -3031,7 +3031,10 @@ scsi_internal_device_unblock(struct scsi_device > > *sdev, > > return -EINVAL; > > > > if (q->mq_ops) { > > - blk_mq_start_stopped_hw_queues(q, false); > > + if (blk_queue_quiesced(q)) > > + blk_mq_unquiesce_queue(q); > > + else > > + blk_mq_start_stopped_hw_queues(q, false); > > } else { > > spin_lock_irqsave(q->queue_lock, flags); > > blk_start_queue(q); > > As I commented on v2, this change is really wrong. All what's needed here is > a call to blk_mq_unquiesce_queue() and nothing else. Adding a call to > blk_mq_start_stopped_hw_queues() is wrong because it makes it impossible to > use the STOPPED flag in the SCSI core to make the block layer core stop > calling > .queue_rq() if a SCSI LLD returns "busy". I am not sure if I understand your idea, could you explain a bit why it is wrong? Let's see the function of scsi_internal_device_block(): if (q->mq_ops) { if (wait) blk_mq_quiesce_queue(q); else blk_mq_stop_hw_queues(q); } So the queue may be put into quiesced if 'wait' is true, or it is stopped if 'wait' is false. And this patch just makes the two SCSI APIs symmetrical. Since we will not stop queue in blk_mq_quiesce_queue() later, I have to unquiese one queue only if it is quiesced. So suppose the queue is put into stopped in scsi_internal_device_block(), do we expect not to restart it in scsi_internal_device_unblock() via blk_mq_unquiesce_queue()? Thanks, Ming
Hello Dear Greetings from the Almighty God
Hello dear greetings to you from the almighty God , my name is Mrs Elvir Cerrato from Honduras i am 45 years old , i ma a dying woman who have decided to donate what i have to the churches , mosque , motherless homes , less privilege and the poor through you i was diagonsed for cancer two years ago but recently my health condition is getting worst by the day ,i have been toched by God to use what he has given me to put a smile on the faces of the poor the needy and the less privilege through you i have asked God to show me a trusted person that will help me and do this humannitarian work because if i die now the money will not used well and the security company where i deposited the money will confiscate the money because no one knows about the fund and i will never be a happy woman in the spirit world because i made a promise to God that i will donate all he has given me to charity organization , the doctor told me that i have less than 30 days to live, at the moment I cannot take any telephone calls right now due to the doctors instructions and my health status also I need you to contact the security company where i deposited my( $3,500,000) with your full name home address where you will like them to ship this trunk box to and your mobile number and i will instruct them to make the delivery of my money to you by quoting my personal reference number:( Jlk/Wds/95773/50015/GwrI/3196 )and I have also notified them that I am willing that amount to you for a good, effective and prudent work. I know I don't know you but I have been directed to do this by God please let me know as soon as you contact the security compmay ok here is the security company's email address (speedex.deliveryandvaultcomp...@mail.ru)
Re: [PATCH] iscsi-target: Fix initial login PDU asynchronous socket close OOPs
On Wed, 2017-05-31 at 15:28 -0500, Mike Christie wrote: > On 05/30/2017 11:58 PM, Nicholas A. Bellinger wrote: > > Hey MNC, > > > > On Fri, 2017-05-26 at 22:14 -0500, Mike Christie wrote: > >> Thanks for the patch. > >> The patch fixes the crash for me. However, is there a possible > >> regression where if the initiator attempts new relogins we could run out > >> of memory? With the old code, we would free the login attempts resources > >> at this time, but with the new code the initiator will send more login > >> attempts and so we just keep allocating more memory for each attempt > >> until we run out or the login is finally able to complete. > > > > AFAICT, no. For the two cases in question: > > > > - Initial login request PDU processing done within iscsi_np kthread > > context in iscsi_target_start_negotiation(), and > > - subsequent login request PDU processing done by delayed work-queue > > kthread context in iscsi_target_do_login_rx() > > > > this patch doesn't change how aggressively connection cleanup happens > > for failed login attempts in the face of new connection login attempts > > for either case. > > > > For the first case when iscsi_np process context invokes > > iscsi_target_start_negotiation() -> iscsi_target_do_login() -> > > iscsi_check_for_session_reinstatement() to wait for backend I/O to > > complete, it still blocks other new connections from being accepted on > > the specific iscsi_np process context. > > > > This patch doesn't change this behavior. > > > > What it does change is when the host closes the connection and > > iscsi_target_sk_state_change() gets invoked, iscsi_np process context > > waits for iscsi_check_for_session_reinstatement() to complete before > > releasing the connection resources. > > > > However since iscsi_np process context is blocked, new connections won't > > be accepted until the new connection forcing session reinstatement > > finishes waiting for outstanding backend I/O to complete. > > I was seeing this. My original mail asked about iscsi login resources > incorrectly, but like you said we do not get that far. I get a giant > backlog (1 connection request per 5 seconds that we waited) of tcp level > connection requests and drops. When the wait is done I get a flood of > "iSCSI Login negotiation failed" due to the target handling all those > now stale requests/drops. Ah, I see what you mean. The TCP backlog = 256 default can fill up when a small host side login timeout is used while iscsi_np is blocked waiting for session reinstatement to complete. > > If we do not care about the memory use at the network level for this > case (it seems like a little and reconnects are not aggressive), then > patch works ok for me. I am guessing it gets nasty to handle, so maybe > not worth it to handle right now? Yeah, since it's a issue separate from root cause here, getting this merged first makes sense. > I tried to do it in my patch which is why it got all crazy with the > waits/wakeups :) > One option to consider is to immediately queue into delayed work-queue context from iscsi_target_start_negotiation() instead of doing the iscsi_target_do_login() and session reinstatement from iscsi_np context. Just taking a quick look, this seems like it would be a pretty straight-forward change.. > Thanks, and you can add a tested-by or reviewed-by from me. Great, thanks MNC. Will send out a PULL request for -rc4 shortly.
Re: [PATCH v2 11/17] qla2xxx: Turn on FW option for exchange check
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > - ctio->u.status1.flags = (atio->u.isp24.attr << 9) | > - cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS); > + temp = (atio->u.isp24.attr << 9)| > + CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS; > + ctio->u.status1.flags = cpu_to_le16(temp); This patch not only includes the functional changes explained in the patch description but also several changes that do not change any functionality like the above. Please keep functional and non-functional changes separate for future patch submissions. Thanks, Bart.
Re: [PATCH v2 06/17] tcm_qla2xxx: Do not allow aborted cmd to advance.
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > From: Quinn Tran> > In case of hardware queue full, commands can loop between > TCM stack and tcm_qla2xx shim layers for retry. While command > is waiting for retry, task mgmt can get ahead and abort the > cmmand that encountered queue full condition. Fix this by > dropping the command, if task mgmt has already started the > command free process. Although I think this is a check that should be performed by the target core instead of each target driver: Reviewed-by: Bart Van Assche
Re: [PATCH v2 05/17] qla2xxx: Fix path recovery
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > From: Quinn Tran> > If the port is moved/changed, current code would trigger > a deletion. If the port is already deleted, then do relogin. Reviewed-by: Bart Van Assche
Re: [PATCH 20/25] qla2xxx: Remove redundant code
Bart, Will make available in the next upstream, once it has a chance to go through our internal test cycle. Regards, Quinn Tran -Original Message- From: Bart Van AsscheDate: Wednesday, May 31, 2017 at 4:41 PM To: "Tran, Quinn" , Nicholas Bellinger Cc: "linux-scsi@vger.kernel.org" , "james.bottom...@hansenpartnership.com" , "Madhani, Himanshu" , "martin.peter...@oracle.com" Subject: Re: [PATCH 20/25] qla2xxx: Remove redundant code On Mon, 2017-05-22 at 22:14 +, Tran, Quinn wrote: > > I think an initiator could get > really confused if it receives two responses for the same exchange. > > QT: I do see the window youʼre describing in the qlt_try_to_dequeue_unknown_atios(). > Will have to follow up with another patch. This patch is not meant for this window > youʼve just identify. Hello Quinn, Has that patch been included in v2 of this series or will that patch perhaps be made available later? Thanks, Bart.
Re: [PATCH v2 03/17] qla2xxx: Retain loop test for fwdump length exceeding buffer length
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > From: Joe CarnuccioReviewed-by: Bart Van Assche
Re: [PATCH v2 02/17] qla2xxx: Replace usage of spin_lock with spin_lock_irqsave
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > From: Quinn Tran> > Convert usage of spin_lock to spin_lock_irqsave because qla2xxx driver > accesses all the data structures in an interrupt context. Did you perhaps mean "*can* access all data structures in interrupt context"? Anyway: Reviewed-by: Bart Van Assche
Re: [PATCH v2 01/17] qla2xxx: Allow ABTS RX, RIDA on ATIOQ for ISP83XX/27XX
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > From: Quinn Tran> > Driver added mechanism to move ABTS/PUREX/RIDA mailbox to > ATIO queue as part of commit id 41dc529a4602ac737020f423f84686a81de38e6d > ("qla2xxx: Improve RSCN handling in driver"). > > This patch addes a check to only allow ABTS/PURX/RIDA > to be moved to ATIO Queue for ISP83XX and ISP27XX. Did you perhaps mean "adds" instead of "adds"? Anyway: Reviewed-by: Bart Van Assche
Re: [PATCH 20/25] qla2xxx: Remove redundant code
On Mon, 2017-05-22 at 22:14 +, Tran, Quinn wrote: > > I think an initiator could get > really confused if it receives two responses for the same exchange. > > QT: I do see the window you’re describing in the > qlt_try_to_dequeue_unknown_atios(). > Will have to follow up with another patch. This patch is not meant for this > window > you’ve just identify. Hello Quinn, Has that patch been included in v2 of this series or will that patch perhaps be made available later? Thanks, Bart.
Re: [PATCH v2 15/17] qla2xxx: Accelerate SCSI BUSY status generation in target mode
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > + /* FW perform Exchang validation */ Did you perhaps intend "exchange" instead of "Exchang"? Please fix this if you repost this patch. Thanks, Bart.
Re: [PATCH v2 13/17] qla2xxx: Remove redundant code
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > The reason for hard coding LUN ID to 0 is that, from the FC > protocol perspective, ABTS does not have any knowledge of > LUN ID. So, there is no reason for qla2xxx driver to > manufacture the LUN ID. Sorry but I think this is completely wrong. Are you aware that target_submit_tmr() performs an exact match on the LUN specified as the fourth argument? This patch will cause ABTS requests to be ignored that apply to commands that have been submitted to another LUN than LUN 0. Please note that I had proposed a better approach three months ago on the target-devel mailing list and that I'm still waiting for someone from Cavium to review these patches: * [PATCH v6 09/33] target: Make it possible to specify I_T nexus for SCSI abort (http://www.spinics.net/lists/target-devel/msg14534.html). * [PATCH v6 10/33] tcm_qla2xxx: Let the target core look up the LUN of the aborted cmd (http://www.spinics.net/lists/target-devel/msg14563.html). Bart.
Re: [PATCH v2 12/17] qla2xxx: Add ql2xiniexchg parameter
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > - "For Dual Mode (qlini_mode=dual), this parameter determines " > - "the percentage of exchanges/cmds FW will allocate resources " > - "for Target mode."); > + "For Dual Mode (qlini_mode=dual), this parameter determines " > + "the percentage of exchanges/cmds FW will allocate resources " > + "for Target mode."); Hello Himanshu and Quinn, There are several pointless changes in this patch series like the above that changes indentation from 7 spaces to five spaces. Please leave such changes out from future patch submissions. Thanks, Bart.
Re: [PATCH v2 08/17] qla2xxx: Convert 32-bit LUN usage to 64-bit
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > From: Quinn TranReviewed-by: Bart Van Assche
Re: [PATCH v2 04/17] qla2xxx: Include Exchange offload/Extended Login into FW dump
On Tue, 2017-05-30 at 10:54 -0700, Himanshu Madhani wrote: > static inline void * > +qla25xx_copy_exlogin(struct qla_hw_data *ha, void *ptr, uint32_t > **last_chain) > +{ > + struct qla2xxx_offld_chain *c = ptr; > + > + if (!ha->exlogin_buf) > + return ptr; > + > + *last_chain = >type; > + > + c->type = htonl(DUMP_CHAIN_EXLOGIN); > + c->chain_size = htonl(sizeof(struct qla2xxx_offld_chain) + > + ha->exlogin_size); > + c->size = htonl(ha->exlogin_size); Since this is not networking code, why is this code using htonl() instead of cpu_to_be32()? > + c->addr_l = htonl(LSD(ha->exlogin_buf_dma)); > + c->addr_h = htonl(MSD(ha->exlogin_buf_dma)); Please use cpu_to_be64() instead of this weird construct. > + uint32_t addr_l; > + uint32_t addr_h; Please declare this as a single 64-bit variable instead of using this weird split into two 32-bit variables. Thanks, Bart.
Re: [PATCH] qla2xxx: Fix extraneous ref on sp's after adapter break
> On May 25, 2017, at 12:26 PM, Bill Kuzejawrote: > > Hung task timeouts can result if a qlogic board breaks unexpectedly while > running I/O. These tasks become hung because command srb reference counts > are not going to zero, hence the affected srbs and commands do not get > freed. This fix accounts for this extra reference in the srbs in the case > of a board failure. > > Fixes: a465537ad1a4 ("qla2xxx: Disable the adapter and skip error recovery in > case of register disconnect") > Signed-off-by: Bill Kuzeja > --- > > I encountered this hang during by adapter break testing (on Stratus > hardware, we need to survive adapter breaks). I noticed that we wait > indefinitely for several commands which all have outstanding > references to them, but which have all followed this code path: > > qla2x00_abort_all_cmds > qla2xxx_eh_abort > Exit early because qla2x00_isp_reg_stat is non-zero. > > Note that before calling qla2xxx_eh_abort from this path, we do an extra > sp_get(sp), which takes out another reference on the current sp. If we > do not early exit immediately from qla2xxx_eh_abort, we'll get rid of this > extra reference through the abort - which is the normal case. > > However, if we exit immediately, this extra sp_get is never dereferenced. > Each one of the commands flowing through this code will be stuck forever, > resulting in hung tasks. > > This early exit in qla2xxx_eh_abort was introduced by this commit: > > commit a465537ad1a4 ("qla2xxx: Disable the adapter and skip error recovery in > case of register disconnect.") > > The solution for this is somewhat tricky because qla2xxx_eh_abort can be > invoked from the scsi error handler as well as qla2x00_abort_all_cmds. > I originally thought of having qla2xxx_eh_abort remove the extra reference > before early exiting, but not knowing the context of its invocation, > this seemed dangerous. > > Alternatively we could also just remove the early exit case from > qla2xxx_eh_abort, but the aforementioned commit was put in for a reason, so > that doesn't seem correct either. > > The right thing to do seems to be putting the fix in qla2x00_abort_all_cmds, > checking the conditions we where we have exited early from qla2xxx_eh_abort > before removing the extra reference. > > --- > drivers/scsi/qla2xxx/qla_os.c | 7 +-- > 1 file changed, 5 insertions(+), 2 deletions(-) > > diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c > index 1c79579..1a93365 100644 > --- a/drivers/scsi/qla2xxx/qla_os.c > +++ b/drivers/scsi/qla2xxx/qla_os.c > @@ -1632,7 +1632,7 @@ uint32_t qla2x00_isp_reg_stat(struct qla_hw_data *ha) > void > qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) > { > - int que, cnt; > + int que, cnt, status; > unsigned long flags; > srb_t *sp; > struct qla_hw_data *ha = vha->hw; > @@ -1662,8 +1662,12 @@ uint32_t qla2x00_isp_reg_stat(struct qla_hw_data *ha) >*/ > sp_get(sp); > > spin_unlock_irqrestore(>hardware_lock, flags); > - qla2xxx_eh_abort(GET_CMD_SP(sp)); > + status = > qla2xxx_eh_abort(GET_CMD_SP(sp)); > spin_lock_irqsave(>hardware_lock, > flags); > + /* Get rid of extra reference if > immediate exit > + * from ql2xxx_eh_abort */ > + if (status == FAILED && > (qla2x00_isp_reg_stat(ha))) > + atomic_dec(>ref_count); > } > req->outstanding_cmds[cnt] = NULL; > sp->done(sp, res); > -- > 1.8.3.1 > Looks Good. Acked-by: Himanshu Madhani Thanks, - Himanshu
Re: [PATCH] iscsi-target: Fix initial login PDU asynchronous socket close OOPs
On 05/30/2017 11:58 PM, Nicholas A. Bellinger wrote: > Hey MNC, > > On Fri, 2017-05-26 at 22:14 -0500, Mike Christie wrote: >> Thanks for the patch. >> > > Btw, after running DATERA's internal longevity and scale tests across > ~20 racks on v4.1.y with this patch over the long weekend, there haven't > been any additional regressions. > >> On 05/26/2017 12:32 AM, Nicholas A. Bellinger wrote: >>> >>> - state = iscsi_target_sk_state_check(sk); >>> - write_unlock_bh(>sk_callback_lock); >>> - >>> - pr_debug("iscsi_target_sk_state_change: state: %d\n", state); >>> + orig_state_change(sk); >>> >>> - if (!state) { >>> - pr_debug("iscsi_target_sk_state_change got failed state\n"); >>> - schedule_delayed_work(>login_cleanup_work, 0); >> >> I think login_cleanup_work is no longer used so you can also remove it >> and its code. > > Yep, since this needs to goto stable, I left that part out for now.. > > Will take care of that post -rc4. > >> >> The patch fixes the crash for me. However, is there a possible >> regression where if the initiator attempts new relogins we could run out >> of memory? With the old code, we would free the login attempts resources >> at this time, but with the new code the initiator will send more login >> attempts and so we just keep allocating more memory for each attempt >> until we run out or the login is finally able to complete. > > AFAICT, no. For the two cases in question: > > - Initial login request PDU processing done within iscsi_np kthread > context in iscsi_target_start_negotiation(), and > - subsequent login request PDU processing done by delayed work-queue > kthread context in iscsi_target_do_login_rx() > > this patch doesn't change how aggressively connection cleanup happens > for failed login attempts in the face of new connection login attempts > for either case. > > For the first case when iscsi_np process context invokes > iscsi_target_start_negotiation() -> iscsi_target_do_login() -> > iscsi_check_for_session_reinstatement() to wait for backend I/O to > complete, it still blocks other new connections from being accepted on > the specific iscsi_np process context. > > This patch doesn't change this behavior. > > What it does change is when the host closes the connection and > iscsi_target_sk_state_change() gets invoked, iscsi_np process context > waits for iscsi_check_for_session_reinstatement() to complete before > releasing the connection resources. > > However since iscsi_np process context is blocked, new connections won't > be accepted until the new connection forcing session reinstatement > finishes waiting for outstanding backend I/O to complete. I was seeing this. My original mail asked about iscsi login resources incorrectly, but like you said we do not get that far. I get a giant backlog (1 connection request per 5 seconds that we waited) of tcp level connection requests and drops. When the wait is done I get a flood of "iSCSI Login negotiation failed" due to the target handling all those now stale requests/drops. If we do not care about the memory use at the network level for this case (it seems like a little and reconnects are not aggressive), then patch works ok for me. I am guessing it gets nasty to handle, so maybe not worth it to handle right now? I tried to do it in my patch which is why it got all crazy with the waits/wakeups :) Thanks, and you can add a tested-by or reviewed-by from me.
Re: [PATCH] scsi: lpfc: Fix crash on PCI hotplug remove path
Actually, I think we solved this in a better manner in this patch in the 11.4.0.0 patch set: PATCH 10/15] lpfc: Fix crash on powering off BFS VM with passthrough device http://marc.info/?l=linux-scsi=149621070910290=2 See if the above patch fixes your error. -- james On 5/29/2017 4:11 PM, James Smart wrote: looks good Signed-off-by: James Smart-- james On 5/28/2017 2:45 PM, Guilherme G. Piccoli wrote: During a PCI hotplug remove event we could have a NULL pointer dereference on lpfc_sli_abort_iocb(), if pring is NULL. This patch adds a check for this case and is able to circumvent the failure and continue the hotplug remove process with success. This issue was introduced after the driver refactor made on commit 895427bd012c ("scsi: lpfc: NVME Initiator: Base modifications"). Fixes: 895427bd012c ("scsi: lpfc: NVME Initiator: Base modifications") Reported-by: Naresh Bannoth Signed-off-by: Guilherme G. Piccoli --- This patch was rebased against Martin's 4.12/scsi-fixes.
Re: [PATCH 1/1] scsi: scsi_debug: Avoid PI being disabled when TGPS is enabled
On Fri, 2017-05-26 at 12:59 -0400, Martin K. Petersen wrote: > It was not possible to enable both T10 PI and TGPS because they share > the same byte in the INQUIRY response. Logically OR the TPGS value > instead of using assignment. > > Reported-by: Ritika Srivastava> Signed-off-by: Martin K. Petersen > --- > drivers/scsi/scsi_debug.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c > index 17249c3650fe..b945d187873f 100644 > --- a/drivers/scsi/scsi_debug.c > +++ b/drivers/scsi/scsi_debug.c > @@ -1404,7 +1404,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct > sdebug_dev_info *devip) > arr[4] = SDEBUG_LONG_INQ_SZ - 5; > arr[5] = (int)have_dif_prot;/* PROTECT bit */ > if (sdebug_vpd_use_hostno == 0) > - arr[5] = 0x10; /* claim: implicit TGPS */ > + arr[5] |= 0x10; /* claim: implicit TGPS */ > arr[6] = 0x10; /* claim: MultiP */ > /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ > arr[7] = 0xa; /* claim: LINKED + CMDQUE */ Code is correct. s/TGPS/TPGS in the subject line and in one place in the patch description. Reviewed-by: Ewan D. Milne
Re: [PATCH v3 3/9] blk-mq: use the introduced blk_mq_unquiesce_queue()
On Wed, 2017-05-31 at 20:37 +0800, Ming Lei wrote: > diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c > index 99e16ac479e3..ffcf05765e2b 100644 > --- a/drivers/scsi/scsi_lib.c > +++ b/drivers/scsi/scsi_lib.c > @@ -3031,7 +3031,10 @@ scsi_internal_device_unblock(struct scsi_device *sdev, > return -EINVAL; > > if (q->mq_ops) { > - blk_mq_start_stopped_hw_queues(q, false); > + if (blk_queue_quiesced(q)) > + blk_mq_unquiesce_queue(q); > + else > + blk_mq_start_stopped_hw_queues(q, false); > } else { > spin_lock_irqsave(q->queue_lock, flags); > blk_start_queue(q); As I commented on v2, this change is really wrong. All what's needed here is a call to blk_mq_unquiesce_queue() and nothing else. Adding a call to blk_mq_start_stopped_hw_queues() is wrong because it makes it impossible to use the STOPPED flag in the SCSI core to make the block layer core stop calling .queue_rq() if a SCSI LLD returns "busy". Bart.
Re: [PATCH 1/1] scsi: scsi_debug: Avoid PI being disabled when TGPS is enabled
On Fri, 2017-05-26 at 12:59 -0400, Martin K. Petersen wrote: > It was not possible to enable both T10 PI and TGPS because they share > the same byte in the INQUIRY response. Logically OR the TPGS value > instead of using assignment. Reviewed-by: Bart Van Assche
[PATCH] scsi: Add STARGET_CREATE_REMOVE state to scsi_target_state
From: "Ewan D. Milne"The addition of the STARGET_REMOVE state had the side effect of introducing a race condition that can cause a crash. scsi_target_reap_ref_release() checks the starget->state to see if it still in STARGET_CREATED, and if so, skips calling transport_remove_device() and device_del(), because the starget->state is only set to STARGET_RUNNING after scsi_target_add() has called device_add() and transport_add_device(). However, if an rport loss occurs while a target is being scanned, it can happen that scsi_remove_target() will be called while the starget is still in the STARGET_CREATED state. In this case, the starget->state will be set to STARGET_REMOVE, and as a result, scsi_target_reap_ref_release() will take the wrong path. The end result is a panic: [ 1255.356653] Oops: [#1] SMP [ 1255.360154] Modules linked in: x86_pkg_temp_thermal kvm_intel kvm irqbypass crc32c_intel [ 1255.393234] CPU: 5 PID: 149 Comm: kworker/u96:4 Tainted: GW 4.11.0+ #8 [ 1255.401879] Hardware name: Dell Inc. PowerEdge R320/08VT7V, BIOS 2.0.22 11/19/2013 [ 1255.410327] Workqueue: scsi_wq_6 fc_scsi_scan_rport [scsi_transport_fc] [ 1255.417720] task: 88060ca8c8c0 task.stack: c900048a8000 [ 1255.424331] RIP: 0010:kernfs_find_ns+0x13/0xc0 [ 1255.429287] RSP: 0018:c900048abbf0 EFLAGS: 00010246 [ 1255.435123] RAX: RBX: RCX: [ 1255.443083] RDX: RSI: 8188d659 RDI: [ 1255.451043] RBP: c900048abc10 R08: R09: 012433fe0025 [ 1255.459005] R10: 25e5a4b5 R11: 25e5a4b5 R12: 8188d659 [ 1255.466972] R13: R14: 8805f55e5088 R15: [ 1255.474931] FS: () GS:880616b4() knlGS: [ 1255.483959] CS: 0010 DS: ES: CR0: 80050033 [ 1255.490370] CR2: 0068 CR3: 01c09000 CR4: 000406e0 [ 1255.498332] Call Trace: [ 1255.501058] kernfs_find_and_get_ns+0x31/0x60 [ 1255.505916] sysfs_unmerge_group+0x1d/0x60 [ 1255.510498] dpm_sysfs_remove+0x22/0x60 [ 1255.514783] device_del+0xf4/0x2e0 [ 1255.518577] ? device_remove_file+0x19/0x20 [ 1255.523241] attribute_container_class_device_del+0x1a/0x20 [ 1255.529457] transport_remove_classdev+0x4e/0x60 [ 1255.534607] ? transport_add_class_device+0x40/0x40 [ 1255.540046] attribute_container_device_trigger+0xb0/0xc0 [ 1255.546069] transport_remove_device+0x15/0x20 [ 1255.551025] scsi_target_reap_ref_release+0x25/0x40 [ 1255.556467] scsi_target_reap+0x2e/0x40 [ 1255.560744] __scsi_scan_target+0xaa/0x5b0 [ 1255.565312] scsi_scan_target+0xec/0x100 [ 1255.569689] fc_scsi_scan_rport+0xb1/0xc0 [scsi_transport_fc] [ 1255.576099] process_one_work+0x14b/0x390 [ 1255.580569] worker_thread+0x4b/0x390 [ 1255.584651] kthread+0x109/0x140 [ 1255.588251] ? rescuer_thread+0x330/0x330 [ 1255.592730] ? kthread_park+0x60/0x60 [ 1255.596815] ret_from_fork+0x29/0x40 [ 1255.600801] Code: 24 08 48 83 42 40 01 5b 41 5c 5d c3 66 66 66 2e 0f 1f 84 00 00 00 00 00 66 66 66 66 90 [ 1255.621876] RIP: kernfs_find_ns+0x13/0xc0 RSP: c900048abbf0 [ 1255.628479] CR2: 0068 [ 1255.632756] ---[ end trace 34a69ba0477d036f ]--- Fix this by adding another scsi_target state STARGET_CREATED_REMOVE to distinguish this case. Fixes: f05795d3d771 ("scsi: Add intermediate STARGET_REMOVE state to scsi_target_state") Reported-by: David Jeffery Signed-off-by: Ewan D. Milne Cc: sta...@vger.kernel.org --- drivers/scsi/scsi_scan.c | 5 +++-- drivers/scsi/scsi_sysfs.c | 8 ++-- include/scsi/scsi_device.h | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 6f7128f..27a6d3c 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -384,11 +384,12 @@ static void scsi_target_reap_ref_release(struct kref *kref) = container_of(kref, struct scsi_target, reap_ref); /* -* if we get here and the target is still in the CREATED state that +* if we get here and the target is still in a CREATED state that * means it was allocated but never made visible (because a scan * turned up no LUNs), so don't call device_del() on it. */ - if (starget->state != STARGET_CREATED) { + if ((starget->state != STARGET_CREATED) && + (starget->state != STARGET_CREATED_REMOVE)) { transport_remove_device(>dev); device_del(>dev); } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 82dfe07..3a6f557 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1370,11 +1370,15 @@ void scsi_remove_target(struct device *dev) spin_lock_irqsave(shost->host_lock, flags); list_for_each_entry(starget, >__targets, siblings) {
[PATCH v3 4/5] tcmu: Make dev_config configurable
This allows for userspace to change the device path after it has been created. Thus giving the user the ability to change the path. The use case for this is to allow for virtual optical to have media change. v3 - Fix kree spelling error to kfree Signed-off-by: Bryant G. Ly--- drivers/target/target_core_user.c | 41 +++ 1 file changed, 41 insertions(+) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index a4cf678..eea4630 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1577,6 +1577,46 @@ static ssize_t tcmu_cmd_time_out_store(struct config_item *item, const char *pag } CONFIGFS_ATTR(tcmu_, cmd_time_out); +static ssize_t tcmu_dev_path_show(struct config_item *item, char *page) +{ + struct se_dev_attrib *da = container_of(to_config_group(item), + struct se_dev_attrib, da_group); + struct tcmu_dev *udev = TCMU_DEV(da->da_dev); + + return snprintf(page, PAGE_SIZE, "%s\n", udev->dev_config); +} + +static ssize_t tcmu_dev_path_store(struct config_item *item, const char *page, + size_t count) +{ + struct se_dev_attrib *da = container_of(to_config_group(item), + struct se_dev_attrib, da_group); + struct tcmu_dev *udev = TCMU_DEV(da->da_dev); + char *copy = NULL; + int ret; + + copy = kstrdup(page, GFP_KERNEL); + if (!copy) { + kfree(copy); + return -EINVAL; + } + strcpy(udev->dev_config, copy); + + /* Check if device has been configured before */ + if (tcmu_dev_configured(udev)) { + ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, +udev->uio_info.name, +udev->uio_info.uio_dev->minor); + if (ret) { + pr_err("Unable to reconfigure device\n"); + return ret; + } + } + + return count; +} +CONFIGFS_ATTR(tcmu_, dev_path); + static ssize_t tcmu_dev_size_show(struct config_item *item, char *page) { struct se_dev_attrib *da = container_of(to_config_group(item), @@ -1655,6 +1695,7 @@ CONFIGFS_ATTR(tcmu_, emulate_write_cache); struct configfs_attribute *tcmu_attrib_attrs[] = { _attr_cmd_time_out, + _attr_dev_path, _attr_dev_size, _attr_emulate_write_cache, NULL, -- 2.5.4 (Apple Git-61)
[PATCH v3 02/23] scsi: hisi_sas: define hisi_sas_device.device_id as int
Currently hisi_sas_device.device_id is a u64. This can create a problem in selecting the queue for a device, in that this code does a 64b division on device id. For some 32b systems, 64b division is slow and the lib reference must be explicitly included. The device id does not need to be 64b in size, so, as a solution, just make as an int. Also, struct hisi_sas_device elements are re-ordered to improve packing efficiency. Signed-off-by: John Garry--- drivers/scsi/hisi_sas/hisi_sas.h | 8 drivers/scsi/hisi_sas/hisi_sas_main.c | 10 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 4e28f32..b4e96fa9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -107,15 +107,15 @@ struct hisi_sas_dq { }; struct hisi_sas_device { - enum sas_device_typedev_type; struct hisi_hba *hisi_hba; struct domain_device*sas_device; + struct list_headlist; u64 attached_phy; - u64 device_id; atomic64_t running_req; - struct list_headlist; - u8 dev_status; + enum sas_device_typedev_type; + int device_id; int sata_idx; + u8 dev_status; }; struct hisi_sas_slot { diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 3605d28..54e0cf2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -209,7 +209,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, if (DEV_IS_GONE(sas_dev)) { if (sas_dev) - dev_info(dev, "task prep: device %llu not ready\n", + dev_info(dev, "task prep: device %d not ready\n", sas_dev->device_id); else dev_info(dev, "task prep: device %016llx not ready\n", @@ -627,9 +627,9 @@ static void hisi_sas_dev_gone(struct domain_device *device) struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = _hba->pdev->dev; - u64 dev_id = sas_dev->device_id; + int dev_id = sas_dev->device_id; - dev_info(dev, "found dev[%lld:%x] is gone\n", + dev_info(dev, "found dev[%d:%x] is gone\n", sas_dev->device_id, sas_dev->dev_type); hisi_sas_internal_task_abort(hisi_hba, device, @@ -1082,7 +1082,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) } out: if (rc != TMF_RESP_FUNC_COMPLETE) - dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n", + dev_err(dev, "lu_reset: for device[%d]:rc= %d\n", sas_dev->device_id, rc); return rc; } @@ -1129,7 +1129,7 @@ static int hisi_sas_query_task(struct sas_task *task) } static int -hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id, +hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, struct sas_task *task, int abort_flag, int task_tag) { -- 1.9.1
[PATCH v3 03/23] scsi: hisi_sas: optimise the usage of hisi_hba.lock
From: Xiang ChenCurrently hisi_hba.lock is locked to deliver and receive a command to/from any hw queue. This causes much contention at high data-rates. To boost performance, lock on a per queue basis for sending and receiving commands to/from hw. Certain critical regions still need to be locked in the delivery and completion stages with hisi_hba.lock. New element hisi_sas_device.dq is added to store the delivery queue for a device, so it does not need to be needlessly re-calculated for every task. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 9 ++--- drivers/scsi/hisi_sas/hisi_sas_main.c | 61 +++--- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 23 + drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 34 +-- 4 files changed, 71 insertions(+), 56 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index b4e96fa9..68ba7bd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -102,6 +102,8 @@ struct hisi_sas_cq { struct hisi_sas_dq { struct hisi_hba *hisi_hba; + struct hisi_sas_slot*slot_prep; + spinlock_t lock; int wr_point; int id; }; @@ -109,6 +111,7 @@ struct hisi_sas_dq { struct hisi_sas_device { struct hisi_hba *hisi_hba; struct domain_device*sas_device; + struct hisi_sas_dq *dq; struct list_headlist; u64 attached_phy; atomic64_t running_req; @@ -154,9 +157,8 @@ struct hisi_sas_hw { struct domain_device *device); struct hisi_sas_device *(*alloc_dev)(struct domain_device *device); void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no); - int (*get_free_slot)(struct hisi_hba *hisi_hba, u32 dev_id, - int *q, int *s); - void (*start_delivery)(struct hisi_hba *hisi_hba); + int (*get_free_slot)(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq); + void (*start_delivery)(struct hisi_sas_dq *dq); int (*prep_ssp)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, int is_tmf, struct hisi_sas_tmf_task *tmf); @@ -217,7 +219,6 @@ struct hisi_hba { struct hisi_sas_port port[HISI_SAS_MAX_PHYS]; int queue_count; - struct hisi_sas_slot*slot_prep; struct dma_pool *sge_page_pool; struct hisi_sas_device devices[HISI_SAS_MAX_DEVICES]; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 54e0cf2..b247220 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -179,10 +179,11 @@ static void hisi_sas_slot_abort(struct work_struct *work) task->task_done(task); } -static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, - int is_tmf, struct hisi_sas_tmf_task *tmf, - int *pass) +static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq + *dq, int is_tmf, struct hisi_sas_tmf_task *tmf, + int *pass) { + struct hisi_hba *hisi_hba = dq->hisi_hba; struct domain_device *device = task->dev; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_port *port; @@ -240,18 +241,24 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, } else n_elem = task->num_scatter; + spin_lock_irqsave(_hba->lock, flags); if (hisi_hba->hw->slot_index_alloc) rc = hisi_hba->hw->slot_index_alloc(hisi_hba, _idx, device); else rc = hisi_sas_slot_index_alloc(hisi_hba, _idx); - if (rc) + if (rc) { + spin_unlock_irqrestore(_hba->lock, flags); goto err_out; - rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id, - _queue, _queue_slot); + } + spin_unlock_irqrestore(_hba->lock, flags); + + rc = hisi_hba->hw->get_free_slot(hisi_hba, dq); if (rc) goto err_out_tag; + dlvry_queue = dq->id; + dlvry_queue_slot = dq->wr_point; slot = _hba->slot_info[slot_idx]; memset(slot, 0, sizeof(struct hisi_sas_slot)); @@ -316,7 +323,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(>task_state_lock, flags); - hisi_hba->slot_prep = slot; + dq->slot_prep = slot; atomic64_inc(_dev->running_req); ++(*pass); @@ -354,19 +361,22 @@ static int hisi_sas_task_exec(struct
[PATCH v3 06/23] scsi: hisi_sas: relocate get_ncq_tag_v2_hw()
From: Xiang ChenRelocate get_ncq_tag_v2_hw() to a common location, as future hw versions will require it. Also rename with "hisi_sas_" prefix for consistency. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 15 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 16 +--- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index f2d69cd..439b1f2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -360,6 +360,7 @@ struct hisi_sas_command_table_ssp { extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); extern void hisi_sas_sata_done(struct sas_task *task, struct hisi_sas_slot *slot); +extern int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag); extern int hisi_sas_probe(struct platform_device *pdev, const struct hisi_sas_hw *ops); extern int hisi_sas_remove(struct platform_device *pdev); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 88ace7c..32962d3 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -103,6 +103,21 @@ void hisi_sas_sata_done(struct sas_task *task, } EXPORT_SYMBOL_GPL(hisi_sas_sata_done); +int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag) +{ + struct ata_queued_cmd *qc = task->uldd_task; + + if (qc) { + if (qc->tf.command == ATA_CMD_FPDMA_WRITE || + qc->tf.command == ATA_CMD_FPDMA_READ) { + *tag = qc->tag; + return 1; + } + } + return 0; +} +EXPORT_SYMBOL_GPL(hisi_sas_get_ncq_tag); + static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) { return device->port->ha->lldd_ha; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index fdd7019..9cc5435 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2332,20 +2332,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, return sts; } -static int get_ncq_tag_v2_hw(struct sas_task *task, u32 *tag) -{ - struct ata_queued_cmd *qc = task->uldd_task; - - if (qc) { - if (qc->tf.command == ATA_CMD_FPDMA_WRITE || - qc->tf.command == ATA_CMD_FPDMA_READ) { - *tag = qc->tag; - return 1; - } - } - return 0; -} - static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) { @@ -2393,7 +2379,7 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba, hdr->dw1 = cpu_to_le32(dw1); /* dw2 */ - if (task->ata_task.use_ncq && get_ncq_tag_v2_hw(task, _tag)) { + if (task->ata_task.use_ncq && hisi_sas_get_ncq_tag(task, _tag)) { task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF; } -- 1.9.1
[PATCH v3 04/23] scsi: hisi_sas: relocate get_ata_protocol()
From: Xiang ChenRelocate get_ata_protocol() to a common location, as future hw versions will require it. Also rename with "hisi_sas_" prefix for consistency. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 65 + drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 67 +- 3 files changed, 68 insertions(+), 65 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 68ba7bd..8ed1199 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -356,6 +356,7 @@ struct hisi_sas_command_table_ssp { struct hisi_sas_command_table_stp stp; }; +extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction); extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); extern int hisi_sas_probe(struct platform_device *pdev, const struct hisi_sas_hw *ops); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index b247220..f71590c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -15,6 +15,12 @@ #define DEV_IS_GONE(dev) \ ((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) +#define SATA_PROTOCOL_NONDATA 0x1 +#define SATA_PROTOCOL_PIO 0x2 +#define SATA_PROTOCOL_DMA 0x4 +#define SATA_PROTOCOL_FPDMA0x8 +#define SATA_PROTOCOL_ATAPI0x10 + static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, u8 *lun, struct hisi_sas_tmf_task *tmf); static int @@ -23,6 +29,65 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, int abort_flag, int tag); static int hisi_sas_softreset_ata_disk(struct domain_device *device); +u8 hisi_sas_get_ata_protocol(u8 cmd, int direction) +{ + switch (cmd) { + case ATA_CMD_FPDMA_WRITE: + case ATA_CMD_FPDMA_READ: + case ATA_CMD_FPDMA_RECV: + case ATA_CMD_FPDMA_SEND: + case ATA_CMD_NCQ_NON_DATA: + return SATA_PROTOCOL_FPDMA; + + case ATA_CMD_DOWNLOAD_MICRO: + case ATA_CMD_ID_ATA: + case ATA_CMD_PMP_READ: + case ATA_CMD_READ_LOG_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_PMP_WRITE: + case ATA_CMD_WRITE_LOG_EXT: + case ATA_CMD_PIO_WRITE: + case ATA_CMD_PIO_WRITE_EXT: + return SATA_PROTOCOL_PIO; + + case ATA_CMD_DSM: + case ATA_CMD_DOWNLOAD_MICRO_DMA: + case ATA_CMD_PMP_READ_DMA: + case ATA_CMD_PMP_WRITE_DMA: + case ATA_CMD_READ: + case ATA_CMD_READ_EXT: + case ATA_CMD_READ_LOG_DMA_EXT: + case ATA_CMD_READ_STREAM_DMA_EXT: + case ATA_CMD_TRUSTED_RCV_DMA: + case ATA_CMD_TRUSTED_SND_DMA: + case ATA_CMD_WRITE: + case ATA_CMD_WRITE_EXT: + case ATA_CMD_WRITE_FUA_EXT: + case ATA_CMD_WRITE_QUEUED: + case ATA_CMD_WRITE_LOG_DMA_EXT: + case ATA_CMD_WRITE_STREAM_DMA_EXT: + return SATA_PROTOCOL_DMA; + + case ATA_CMD_CHK_POWER: + case ATA_CMD_DEV_RESET: + case ATA_CMD_EDD: + case ATA_CMD_FLUSH: + case ATA_CMD_FLUSH_EXT: + case ATA_CMD_VERIFY: + case ATA_CMD_VERIFY_EXT: + case ATA_CMD_SET_FEATURES: + case ATA_CMD_STANDBY: + case ATA_CMD_STANDBYNOW1: + return SATA_PROTOCOL_NONDATA; + default: + if (direction == DMA_NONE) + return SATA_PROTOCOL_NONDATA; + return SATA_PROTOCOL_PIO; + } +} +EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol); + static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) { return device->port->ha->lldd_ha; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 2607aac..d9314c4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -554,12 +554,6 @@ enum { #define DIR_TO_DEVICE 2 #define DIR_RESERVED 3 -#define SATA_PROTOCOL_NONDATA 0x1 -#define SATA_PROTOCOL_PIO 0x2 -#define SATA_PROTOCOL_DMA 0x4 -#define SATA_PROTOCOL_FPDMA0x8 -#define SATA_PROTOCOL_ATAPI0x10 - #define ERR_ON_TX_PHASE(err_phase) (err_phase == 0x2 || \ err_phase == 0x4 || err_phase == 0x8 ||\ err_phase == 0x6 || err_phase == 0xa) @@ -2352,64 +2346,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, return sts; } -static u8 get_ata_protocol(u8 cmd, int direction) -{ - switch (cmd) { - case ATA_CMD_FPDMA_WRITE: - case ATA_CMD_FPDMA_READ: - case ATA_CMD_FPDMA_RECV: - case ATA_CMD_FPDMA_SEND: - case ATA_CMD_NCQ_NON_DATA: -
[PATCH v3 07/23] scsi: hisi_sas: add pci_dev in hisi_hba struct
Since hip08 SAS controller is based on pci device, add hisi_hba.pci_dev for hip08 (will be v3), and also rename hisi_hba.pdev to .platform_dev for clarity. In addition, for common code which wants to reference the controller device struct, add hisi_hba.dev, and change the common code to use it. Signed-off-by: John GarrySigned-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas.h | 6 - drivers/scsi/hisi_sas/hisi_sas_main.c | 36 ++-- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 28 +++--- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 44 +- 4 files changed, 59 insertions(+), 55 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 439b1f2..7b63656 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -190,7 +191,10 @@ struct hisi_hba { /* This must be the first element, used by SHOST_TO_SAS_HA */ struct sas_ha_struct *p; - struct platform_device *pdev; + struct platform_device *platform_dev; + struct pci_dev *pci_dev; + struct device *dev; + void __iomem *regs; struct regmap *ctrl; u32 ctrl_reset_reg; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 32962d3..eefab13 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -174,7 +174,7 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, { if (task) { - struct device *dev = _hba->pdev->dev; + struct device *dev = hisi_hba->dev; struct domain_device *device = task->dev; struct hisi_sas_device *sas_dev = device->lldd_dev; @@ -251,7 +251,7 @@ static void hisi_sas_slot_abort(struct work_struct *work) struct scsi_cmnd *cmnd = task->uldd_task; struct hisi_sas_tmf_task tmf_task; struct scsi_lun lun; - struct device *dev = _hba->pdev->dev; + struct device *dev = hisi_hba->dev; int tag = abort_slot->idx; unsigned long flags; @@ -285,7 +285,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq struct hisi_sas_slot *slot; struct hisi_sas_cmd_hdr *cmd_hdr_base; struct asd_sas_port *sas_port = device->port; - struct device *dev = _hba->pdev->dev; + struct device *dev = hisi_hba->dev; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; unsigned long flags; @@ -455,7 +455,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, u32 pass = 0; unsigned long flags; struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev); - struct device *dev = _hba->pdev->dev; + struct device *dev = hisi_hba->dev; struct domain_device *device = task->dev; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_dq *dq = sas_dev->dq; @@ -550,7 +550,7 @@ static int hisi_sas_dev_found(struct domain_device *device) struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct domain_device *parent_dev = device->parent; struct hisi_sas_device *sas_dev; - struct device *dev = _hba->pdev->dev; + struct device *dev = hisi_hba->dev; if (hisi_hba->hw->alloc_dev) sas_dev = hisi_hba->hw->alloc_dev(device); @@ -735,7 +735,7 @@ static void hisi_sas_dev_gone(struct domain_device *device) { struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); - struct device *dev = _hba->pdev->dev; + struct device *dev = hisi_hba->dev; int dev_id = sas_dev->device_id; dev_info(dev, "found dev[%d:%x] is gone\n", @@ -818,7 +818,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, { struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = sas_dev->hisi_hba; - struct device *dev = _hba->pdev->dev; + struct device *dev = hisi_hba->dev; struct sas_task *task; int res, retry; @@ -935,7 +935,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) struct ata_link *link; int rc = TMF_RESP_FUNC_FAILED; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); - struct device *dev = _hba->pdev->dev; + struct device *dev = hisi_hba->dev; int s = sizeof(struct host_to_dev_fis); unsigned long flags; @@ -993,7 +993,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) return -1; if (!test_and_set_bit(HISI_SAS_RESET_BIT, _hba->flags)) { - struct device *dev = _hba->pdev->dev; +
[PATCH v3 08/23] scsi: hisi_sas: create hisi_sas_get_fw_info()
Move the functionality to retrieve the fw info into a dedicated device type-agnostic function, hisi_sas_get_fw_info(). The reasoning is that this function will be required for future pci-based platforms. Also add some debug logs for failure. Signed-off-by: John Garry--- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 107 ++ 2 files changed, 71 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 7b63656..480f9ae 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -365,6 +365,7 @@ struct hisi_sas_command_table_ssp { extern void hisi_sas_sata_done(struct sas_task *task, struct hisi_sas_slot *slot); extern int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag); +extern int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba); extern int hisi_sas_probe(struct platform_device *pdev, const struct hisi_sas_hw *ops); extern int hisi_sas_remove(struct platform_device *pdev); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index eefab13..5979ab6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1731,66 +1731,99 @@ static void hisi_sas_rst_work_handler(struct work_struct *work) hisi_sas_controller_reset(hisi_hba); } -static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, - const struct hisi_sas_hw *hw) +int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba) { - struct resource *res; - struct Scsi_Host *shost; - struct hisi_hba *hisi_hba; - struct device *dev = >dev; - struct device_node *np = pdev->dev.of_node; + struct device *dev = hisi_hba->dev; + struct platform_device *pdev = hisi_hba->platform_dev; + struct device_node *np = pdev ? pdev->dev.of_node : NULL; struct clk *refclk; - shost = scsi_host_alloc(_sas_sht, sizeof(*hisi_hba)); - if (!shost) { - dev_err(dev, "scsi host alloc failed\n"); - return NULL; - } - hisi_hba = shost_priv(shost); - - INIT_WORK(_hba->rst_work, hisi_sas_rst_work_handler); - hisi_hba->hw = hw; - hisi_hba->platform_dev = pdev; - hisi_hba->dev = dev; - hisi_hba->shost = shost; - SHOST_TO_SAS_HA(shost) = _hba->sha; - - init_timer(_hba->timer); - if (device_property_read_u8_array(dev, "sas-addr", hisi_hba->sas_addr, - SAS_ADDR_SIZE)) - goto err_out; + SAS_ADDR_SIZE)) { + dev_err(dev, "could not get property sas-addr\n"); + return -ENOENT; + } if (np) { + /* +* These properties are only required for platform device-based +* controller with DT firmware. +*/ hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(np, "hisilicon,sas-syscon"); - if (IS_ERR(hisi_hba->ctrl)) - goto err_out; + if (IS_ERR(hisi_hba->ctrl)) { + dev_err(dev, "could not get syscon\n"); + return -ENOENT; + } if (device_property_read_u32(dev, "ctrl-reset-reg", -_hba->ctrl_reset_reg)) - goto err_out; +_hba->ctrl_reset_reg)) { + dev_err(dev, + "could not get property ctrl-reset-reg\n"); + return -ENOENT; + } if (device_property_read_u32(dev, "ctrl-reset-sts-reg", -_hba->ctrl_reset_sts_reg)) - goto err_out; +_hba->ctrl_reset_sts_reg)) { + dev_err(dev, + "could not get property ctrl-reset-sts-reg\n"); + return -ENOENT; + } if (device_property_read_u32(dev, "ctrl-clock-ena-reg", -_hba->ctrl_clock_ena_reg)) - goto err_out; +_hba->ctrl_clock_ena_reg)) { + dev_err(dev, + "could not get property ctrl-clock-ena-reg\n"); + return -ENOENT; + } } - refclk = devm_clk_get(>dev, NULL); + refclk = devm_clk_get(dev, NULL); if (IS_ERR(refclk)) dev_dbg(dev, "no ref clk property\n"); else
[PATCH v3 01/23] scsi: hisi_sas: fix timeout check in hisi_sas_internal_task_abort()
From: Xiang ChenWe need to check for timeout before task status, or the task will be mistook as completed internal abort command. Also add protection for sas_task.task_state_flags in hisi_sas_tmf_timedout(). Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_main.c | 25 + 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f720d3c..3605d28 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -691,8 +691,13 @@ static void hisi_sas_task_done(struct sas_task *task) static void hisi_sas_tmf_timedout(unsigned long data) { struct sas_task *task = (struct sas_task *)data; + unsigned long flags; + + spin_lock_irqsave(>task_state_lock, flags); + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + spin_unlock_irqrestore(>task_state_lock, flags); - task->task_state_flags |= SAS_TASK_STATE_ABORTED; complete(>slow_task->completion); } @@ -1247,6 +1252,17 @@ static int hisi_sas_query_task(struct sas_task *task) wait_for_completion(>slow_task->completion); res = TMF_RESP_FUNC_FAILED; + /* Internal abort timed out */ + if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + struct hisi_sas_slot *slot = task->lldd_task; + + if (slot) + slot->task = NULL; + dev_err(dev, "internal task abort: timeout.\n"); + } + } + if (task->task_status.resp == SAS_TASK_COMPLETE && task->task_status.stat == TMF_RESP_FUNC_COMPLETE) { res = TMF_RESP_FUNC_COMPLETE; @@ -1259,13 +1275,6 @@ static int hisi_sas_query_task(struct sas_task *task) goto exit; } - /* Internal abort timed out */ - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - dev_err(dev, "internal task abort: timeout.\n"); - } - } - exit: dev_dbg(dev, "internal task abort: task to dev %016llx task=%p " "resp: 0x%x sts 0x%x\n", -- 1.9.1
[PATCH v3 09/23] scsi: hisi_sas: add skeleton v3 hw driver
Add skeleton driver for v3 hw in hisi_sas_v3_hw.c File hisi_sas_v3_hw.c will serve 2 purposes: - probing and initialisation of the controller based on pci device - hw layer for v3-based controllers The controller design is quite similar to v2 hw in hip07. However key differences include: -All v2 hw bugs are fixed (hopefully), so workarounds are not required -support for device deregistration -some interrupt modifications -configurable max device support Signed-off-by: John GarrySigned-off-by: Xiang Chen --- drivers/scsi/hisi_sas/Kconfig | 10 +++- drivers/scsi/hisi_sas/Makefile | 1 + drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 47 ++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig index 975dbf0..a5ca080 100644 --- a/drivers/scsi/hisi_sas/Kconfig +++ b/drivers/scsi/hisi_sas/Kconfig @@ -6,4 +6,12 @@ config SCSI_HISI_SAS select BLK_DEV_INTEGRITY depends on ATA help - This driver supports HiSilicon's SAS HBA + This driver supports HiSilicon's SAS HBA, including support based + on platform device + +config SCSI_HISI_SAS_PCI + tristate "HiSilicon SAS on PCI bus" + depends on SCSI_HISI_SAS + depends on PCI + help + This driver supports HiSilicon's SAS HBA based on PCI device diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile index c6d3a1b..24623f2 100644 --- a/drivers/scsi/hisi_sas/Makefile +++ b/drivers/scsi/hisi_sas/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_SCSI_HISI_SAS)+= hisi_sas_main.o obj-$(CONFIG_SCSI_HISI_SAS)+= hisi_sas_v1_hw.o hisi_sas_v2_hw.o +obj-$(CONFIG_SCSI_HISI_SAS_PCI)+= hisi_sas_v3_hw.o diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c new file mode 100644 index 000..cf72577 --- /dev/null +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include "hisi_sas.h" +#define DRV_NAME "hisi_sas_v3_hw" + +static int +hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + return 0; +} + +static void hisi_sas_v3_remove(struct pci_dev *pdev) +{ +} + +enum { + /* instances of the controller */ + hip08, +}; + +static const struct pci_device_id sas_v3_pci_table[] = { + { PCI_VDEVICE(HUAWEI, 0xa230), hip08 }, + {} +}; + +static struct pci_driver sas_v3_pci_driver = { + .name = DRV_NAME, + .id_table = sas_v3_pci_table, + .probe = hisi_sas_v3_probe, + .remove = hisi_sas_v3_remove, +}; + +module_pci_driver(sas_v3_pci_driver); + +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Garry "); +MODULE_DESCRIPTION("HISILICON SAS controller v3 hw driver based on pci device"); +MODULE_ALIAS("platform:" DRV_NAME); -- 1.9.1
[PATCH v3 05/23] scsi: hisi_sas: relocate sata_done_v2_hw()
From: Xiang ChenRelocate get_ata_protocol() to a common location, as future hw versions will require it. Also rename with "hisi_sas_" prefix for consistency. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 2 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 15 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 18 ++ 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 8ed1199..f2d69cd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -358,6 +358,8 @@ struct hisi_sas_command_table_ssp { extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction); extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); +extern void hisi_sas_sata_done(struct sas_task *task, + struct hisi_sas_slot *slot); extern int hisi_sas_probe(struct platform_device *pdev, const struct hisi_sas_hw *ops); extern int hisi_sas_remove(struct platform_device *pdev); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f71590c..88ace7c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -88,6 +88,21 @@ u8 hisi_sas_get_ata_protocol(u8 cmd, int direction) } EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol); +void hisi_sas_sata_done(struct sas_task *task, + struct hisi_sas_slot *slot) +{ + struct task_status_struct *ts = >task_status; + struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf; + struct dev_to_host_fis *d2h = slot->status_buffer + + sizeof(struct hisi_sas_err_record); + + resp->frame_len = sizeof(struct dev_to_host_fis); + memcpy(>ending_fis[0], d2h, sizeof(struct dev_to_host_fis)); + + ts->buf_valid_size = sizeof(*resp); +} +EXPORT_SYMBOL_GPL(hisi_sas_sata_done); + static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) { return device->port->ha->lldd_ha; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index d9314c4..fdd7019 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1683,20 +1683,6 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba, return 0; } -static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task, - struct hisi_sas_slot *slot) -{ - struct task_status_struct *ts = >task_status; - struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf; - struct dev_to_host_fis *d2h = slot->status_buffer + - sizeof(struct hisi_sas_err_record); - - resp->frame_len = sizeof(struct dev_to_host_fis); - memcpy(>ending_fis[0], d2h, sizeof(struct dev_to_host_fis)); - - ts->buf_valid_size = sizeof(*resp); -} - #define TRANS_TX_ERR 0 #define TRANS_RX_ERR 1 #define DMA_TX_ERR 2 @@ -2189,7 +2175,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, break; } } - sata_done_v2_hw(hisi_hba, task, slot); + hisi_sas_sata_done(task, slot); } break; default: @@ -2317,7 +2303,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { ts->stat = SAM_STAT_GOOD; - sata_done_v2_hw(hisi_hba, task, slot); + hisi_sas_sata_done(task, slot); break; } default: -- 1.9.1
[PATCH v3 23/23] scsi: hisi_sas: modify internal abort dev flow for v3 hw
From: Xiang ChenThere is a change for abort dev for v3 hw: add registers to configure unaborted iptt for a device, and then inform this to logic. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 2 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 15 +++ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 28 3 files changed, 45 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index d7545ff..cf2a593 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -182,6 +182,8 @@ struct hisi_sas_hw { void (*free_device)(struct hisi_hba *hisi_hba, struct hisi_sas_device *dev); int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id); + void (*dereg_device)(struct hisi_hba *hisi_hba, + struct domain_device *device); int (*soft_reset)(struct hisi_hba *hisi_hba); int max_command_entries; int complete_hdr_size; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index b90eb50..96a23af 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -763,6 +763,13 @@ static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba) } } +static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba, + struct domain_device *device) +{ + if (hisi_hba->hw->dereg_device) + hisi_hba->hw->dereg_device(hisi_hba, device); +} + static void hisi_sas_dev_gone(struct domain_device *device) { struct hisi_sas_device *sas_dev = device->lldd_dev; @@ -776,6 +783,8 @@ static void hisi_sas_dev_gone(struct domain_device *device) hisi_sas_internal_task_abort(hisi_hba, device, HISI_SAS_INT_ABT_DEV, 0); + hisi_sas_dereg_device(hisi_hba, device); + hisi_hba->hw->free_device(hisi_hba, sas_dev); device->lldd_dev = NULL; memset(sas_dev, 0, sizeof(*sas_dev)); @@ -1107,6 +1116,7 @@ static int hisi_sas_abort_task(struct sas_task *task) if (task->dev->dev_type == SAS_SATA_DEV) { hisi_sas_internal_task_abort(hisi_hba, device, HISI_SAS_INT_ABT_DEV, 0); + hisi_sas_dereg_device(hisi_hba, device); rc = hisi_sas_softreset_ata_disk(device); } } else if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SMP) { @@ -1173,6 +1183,10 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) return TMF_RESP_FUNC_FAILED; sas_dev->dev_status = HISI_SAS_DEV_NORMAL; + hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_DEV, 0); + hisi_sas_dereg_device(hisi_hba, device); + rc = hisi_sas_debug_I_T_nexus_reset(device); if (rc == TMF_RESP_FUNC_COMPLETE) { @@ -1200,6 +1214,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) HISI_SAS_INT_ABT_DEV, 0); if (rc == TMF_RESP_FUNC_FAILED) goto out; + hisi_sas_dereg_device(hisi_hba, device); phy = sas_get_local_phy(device); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 17f9ac9..63239ca 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -50,6 +50,10 @@ #define CFG_ABT_SET_QUERY_IPTT 0xd4 #define CFG_SET_ABORTED_IPTT_OFF 0 #define CFG_SET_ABORTED_IPTT_MSK (0xfff << CFG_SET_ABORTED_IPTT_OFF) +#define CFG_SET_ABORTED_EN_OFF 12 +#define CFG_ABT_SET_IPTT_DONE 0xd8 +#define CFG_ABT_SET_IPTT_DONE_OFF 0 +#define HGC_IOMB_PROC1_STATUS 0x104 #define CFG_1US_TIMER_TRSH 0xcc #define HGC_LM_DFX_STATUS2 0x128 #define HGC_LM_DFX_STATUS2_IOSTLIST_OFF0 @@ -635,6 +639,29 @@ static void free_device_v3_hw(struct hisi_hba *hisi_hba, } } +static void dereg_device_v3_hw(struct hisi_hba *hisi_hba, + struct domain_device *device) +{ + struct hisi_sas_slot *slot, *slot2; + struct hisi_sas_device *sas_dev = device->lldd_dev; + u32 cfg_abt_set_query_iptt; + + cfg_abt_set_query_iptt = hisi_sas_read32(hisi_hba, + CFG_ABT_SET_QUERY_IPTT); + list_for_each_entry_safe(slot, slot2, _dev->list, entry) { + cfg_abt_set_query_iptt &= ~CFG_SET_ABORTED_IPTT_MSK; + cfg_abt_set_query_iptt |= (1 << CFG_SET_ABORTED_EN_OFF) | + (slot->idx << CFG_SET_ABORTED_IPTT_OFF); +
[PATCH v3 21/23] scsi: hisi_sas: Add v3 code to support ECC and AXI bus fatal error
From: Xiang ChenFor ECC 1bit error, logic can recover it, so we only print a warning. For ECC multi-bit and AXI bus fatal error, we panic. Note: once v3 hw controller reset support is added, the panic will be replaced by a controller reset, like v2 hw. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 402 - 1 file changed, 400 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index f71f1ba..3203221 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -51,7 +51,39 @@ #define CFG_SET_ABORTED_IPTT_OFF 0 #define CFG_SET_ABORTED_IPTT_MSK (0xfff << CFG_SET_ABORTED_IPTT_OFF) #define CFG_1US_TIMER_TRSH 0xcc +#define HGC_LM_DFX_STATUS2 0x128 +#define HGC_LM_DFX_STATUS2_IOSTLIST_OFF0 +#define HGC_LM_DFX_STATUS2_IOSTLIST_MSK(0xfff <<\ + HGC_LM_DFX_STATUS2_IOSTLIST_OFF) +#define HGC_LM_DFX_STATUS2_ITCTLIST_OFF12 +#define HGC_LM_DFX_STATUS2_ITCTLIST_MSK(0x7ff <<\ + HGC_LM_DFX_STATUS2_ITCTLIST_OFF) +#define HGC_CQE_ECC_ADDR 0x13c +#define HGC_CQE_ECC_1B_ADDR_OFF0 +#define HGC_CQE_ECC_1B_ADDR_MSK(0x3f << HGC_CQE_ECC_1B_ADDR_OFF) +#define HGC_CQE_ECC_MB_ADDR_OFF8 +#define HGC_CQE_ECC_MB_ADDR_MSK(0x3f << HGC_CQE_ECC_MB_ADDR_OFF) +#define HGC_IOST_ECC_ADDR 0x140 +#define HGC_IOST_ECC_1B_ADDR_OFF 0 +#define HGC_IOST_ECC_1B_ADDR_MSK (0x3ff << HGC_IOST_ECC_1B_ADDR_OFF) +#define HGC_IOST_ECC_MB_ADDR_OFF 16 +#define HGC_IOST_ECC_MB_ADDR_MSK (0x3ff << HGC_IOST_ECC_MB_ADDR_OFF) +#define HGC_DQE_ECC_ADDR 0x144 +#define HGC_DQE_ECC_1B_ADDR_OFF0 +#define HGC_DQE_ECC_1B_ADDR_MSK(0xfff << HGC_DQE_ECC_1B_ADDR_OFF) +#define HGC_DQE_ECC_MB_ADDR_OFF16 +#define HGC_DQE_ECC_MB_ADDR_MSK(0xfff << HGC_DQE_ECC_MB_ADDR_OFF) #define CHNL_INT_STATUS0x148 +#define HGC_ITCT_ECC_ADDR 0x150 +#define HGC_ITCT_ECC_1B_ADDR_OFF 0 +#define HGC_ITCT_ECC_1B_ADDR_MSK (0x3ff << HGC_ITCT_ECC_1B_ADDR_OFF) +#define HGC_ITCT_ECC_MB_ADDR_OFF 16 +#define HGC_ITCT_ECC_MB_ADDR_MSK (0x3ff << HGC_ITCT_ECC_MB_ADDR_OFF) +#define HGC_AXI_FIFO_ERR_INFO 0x154 +#define AXI_ERR_INFO_OFF 0 +#define AXI_ERR_INFO_MSK (0xff << AXI_ERR_INFO_OFF) +#define FIFO_ERR_INFO_OFF 8 +#define FIFO_ERR_INFO_MSK (0xff << FIFO_ERR_INFO_OFF) #define INT_COAL_EN0x19c #define OQ_INT_COAL_TIME 0x1a0 #define OQ_INT_COAL_CNT0x1a4 @@ -85,6 +117,26 @@ #define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF) #define SAS_ECC_INTR 0x1e8 #define SAS_ECC_INTR_MSK 0x1ec +#define SAS_ECC_INTR_DQE_ECC_1B_OFF0 +#define SAS_ECC_INTR_DQE_ECC_MB_OFF1 +#define SAS_ECC_INTR_IOST_ECC_1B_OFF 2 +#define SAS_ECC_INTR_IOST_ECC_MB_OFF 3 +#define SAS_ECC_INTR_ITCT_ECC_MB_OFF 4 +#define SAS_ECC_INTR_ITCT_ECC_1B_OFF 5 +#define SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF 6 +#define SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF 7 +#define SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF 8 +#define SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF 9 +#define SAS_ECC_INTR_CQE_ECC_1B_OFF10 +#define SAS_ECC_INTR_CQE_ECC_MB_OFF11 +#define SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF 12 +#define SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF 13 +#define SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF 14 +#define SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF 15 +#define SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF 16 +#define SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF 17 +#define SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF 18 +#define SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF 19 #define HGC_ERR_STAT_EN0x238 #define DLVRY_Q_0_BASE_ADDR_LO 0x260 #define DLVRY_Q_0_BASE_ADDR_HI 0x264 @@ -98,6 +150,20 @@ #define COMPL_Q_0_DEPTH0x4e8 #define COMPL_Q_0_WR_PTR 0x4ec #define COMPL_Q_0_RD_PTR 0x4f0 +#define HGC_RXM_DFX_STATUS14 0xae8 +#define HGC_RXM_DFX_STATUS14_MEM0_OFF 0 +#define HGC_RXM_DFX_STATUS14_MEM0_MSK (0x1ff <<\ + HGC_RXM_DFX_STATUS14_MEM0_OFF) +#define HGC_RXM_DFX_STATUS14_MEM1_OFF 9 +#define HGC_RXM_DFX_STATUS14_MEM1_MSK (0x1ff <<\ + HGC_RXM_DFX_STATUS14_MEM1_OFF) +#define HGC_RXM_DFX_STATUS14_MEM2_OFF 18 +#define HGC_RXM_DFX_STATUS14_MEM2_MSK
[PATCH v3 18/23] scsi: hisi_sas: add v3 code for itct setup and free
From: Xiang ChenAdd code to itct setup and free for v3 hw. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 114 + 1 file changed, 114 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 613c625..720abd1c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -24,6 +24,11 @@ #define PHY_PORT_NUM_MA0x28 #define PHY_CONN_RATE 0x30 #define AXI_AHB_CLK_CFG0x3c +#define ITCT_CLR 0x44 +#define ITCT_CLR_EN_OFF16 +#define ITCT_CLR_EN_MSK(0x1 << ITCT_CLR_EN_OFF) +#define ITCT_DEV_OFF 0 +#define ITCT_DEV_MSK (0x7ff << ITCT_DEV_OFF) #define AXI_USER1 0x48 #define AXI_USER2 0x4c #define IO_SATA_BROKEN_MSG_ADDR_LO 0x58 @@ -226,6 +231,26 @@ #define CMPLT_HDR_IO_IN_TARGET_OFF 17 #define CMPLT_HDR_IO_IN_TARGET_MSK (0x1 << CMPLT_HDR_IO_IN_TARGET_OFF) +/* ITCT header */ +/* qw0 */ +#define ITCT_HDR_DEV_TYPE_OFF 0 +#define ITCT_HDR_DEV_TYPE_MSK (0x3 << ITCT_HDR_DEV_TYPE_OFF) +#define ITCT_HDR_VALID_OFF 2 +#define ITCT_HDR_VALID_MSK (0x1 << ITCT_HDR_VALID_OFF) +#define ITCT_HDR_MCR_OFF 5 +#define ITCT_HDR_MCR_MSK (0xf << ITCT_HDR_MCR_OFF) +#define ITCT_HDR_VLN_OFF 9 +#define ITCT_HDR_VLN_MSK (0xf << ITCT_HDR_VLN_OFF) +#define ITCT_HDR_SMP_TIMEOUT_OFF 16 +#define ITCT_HDR_AWT_CONTINUE_OFF 25 +#define ITCT_HDR_PORT_ID_OFF 28 +#define ITCT_HDR_PORT_ID_MSK (0xf << ITCT_HDR_PORT_ID_OFF) +/* qw2 */ +#define ITCT_HDR_INLT_OFF 0 +#define ITCT_HDR_INLT_MSK (0xULL << ITCT_HDR_INLT_OFF) +#define ITCT_HDR_RTOLT_OFF 48 +#define ITCT_HDR_RTOLT_MSK (0xULL << ITCT_HDR_RTOLT_OFF) + struct hisi_sas_complete_v3_hdr { __le32 dw0; __le32 dw1; @@ -444,6 +469,93 @@ static void config_id_frame_v3_hw(struct hisi_hba *hisi_hba, int phy_no) __swab32(identify_buffer[5])); } +static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, +struct hisi_sas_device *sas_dev) +{ + struct domain_device *device = sas_dev->sas_device; + struct device *dev = hisi_hba->dev; + u64 qw0, device_id = sas_dev->device_id; + struct hisi_sas_itct *itct = _hba->itct[device_id]; + struct domain_device *parent_dev = device->parent; + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); + + memset(itct, 0, sizeof(*itct)); + + /* qw0 */ + qw0 = 0; + switch (sas_dev->dev_type) { + case SAS_END_DEVICE: + case SAS_EDGE_EXPANDER_DEVICE: + case SAS_FANOUT_EXPANDER_DEVICE: + qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF; + break; + case SAS_SATA_DEV: + case SAS_SATA_PENDING: + if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; + else + qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF; + break; + default: + dev_warn(dev, "setup itct: unsupported dev type (%d)\n", +sas_dev->dev_type); + } + + qw0 |= ((1 << ITCT_HDR_VALID_OFF) | + (device->linkrate << ITCT_HDR_MCR_OFF) | + (1 << ITCT_HDR_VLN_OFF) | + (0xfa << ITCT_HDR_SMP_TIMEOUT_OFF) | + (1 << ITCT_HDR_AWT_CONTINUE_OFF) | + (port->id << ITCT_HDR_PORT_ID_OFF)); + itct->qw0 = cpu_to_le64(qw0); + + /* qw1 */ + memcpy(>sas_addr, device->sas_addr, SAS_ADDR_SIZE); + itct->sas_addr = __swab64(itct->sas_addr); + + /* qw2 */ + if (!dev_is_sata(device)) + itct->qw2 = cpu_to_le64((5000ULL << ITCT_HDR_INLT_OFF) | + (0x1ULL << ITCT_HDR_RTOLT_OFF)); +} + +static void free_device_v3_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_device *sas_dev) +{ + u64 dev_id = sas_dev->device_id; + struct device *dev = hisi_hba->dev; + struct hisi_sas_itct *itct = _hba->itct[dev_id]; + u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); + + /* clear the itct interrupt state */ + if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) + hisi_sas_write32(hisi_hba, ENT_INT_SRC3, +ENT_INT_SRC3_ITC_INT_MSK); + + /* clear the itct table*/ + reg_val = hisi_sas_read32(hisi_hba,
[PATCH v3 15/23] scsi: hisi_sas: add v3 code to send SSP frame
From: Xiang ChenAdd code to prepare SSP frame and deliver it to hardware. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 208 + 1 file changed, 208 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 4259047..7be3a53 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -157,6 +157,41 @@ #define SL_RX_BCAST_CHK_MSK(PORT_BASE + 0x2c0) #define PHYCTRL_OOB_RESTART_MSK(PORT_BASE + 0x2c4) +/* HW dma structures */ +/* Delivery queue header */ +/* dw0 */ +#define CMD_HDR_RESP_REPORT_OFF5 +#define CMD_HDR_RESP_REPORT_MSK(0x1 << CMD_HDR_RESP_REPORT_OFF) +#define CMD_HDR_TLR_CTRL_OFF 6 +#define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF) +#define CMD_HDR_PORT_OFF 18 +#define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF) +#define CMD_HDR_PRIORITY_OFF 27 +#define CMD_HDR_PRIORITY_MSK (0x1 << CMD_HDR_PRIORITY_OFF) +#define CMD_HDR_CMD_OFF29 +#define CMD_HDR_CMD_MSK(0x7 << CMD_HDR_CMD_OFF) +/* dw1 */ +#define CMD_HDR_DIR_OFF5 +#define CMD_HDR_DIR_MSK(0x3 << CMD_HDR_DIR_OFF) +#define CMD_HDR_VDTL_OFF 10 +#define CMD_HDR_VDTL_MSK (0x1 << CMD_HDR_VDTL_OFF) +#define CMD_HDR_FRAME_TYPE_OFF 11 +#define CMD_HDR_FRAME_TYPE_MSK (0x1f << CMD_HDR_FRAME_TYPE_OFF) +#define CMD_HDR_DEV_ID_OFF 16 +#define CMD_HDR_DEV_ID_MSK (0x << CMD_HDR_DEV_ID_OFF) +/* dw2 */ +#define CMD_HDR_CFL_OFF0 +#define CMD_HDR_CFL_MSK(0x1ff << CMD_HDR_CFL_OFF) +#define CMD_HDR_MRFL_OFF 15 +#define CMD_HDR_MRFL_MSK (0x1ff << CMD_HDR_MRFL_OFF) +#define CMD_HDR_SG_MOD_OFF 24 +#define CMD_HDR_SG_MOD_MSK (0x3 << CMD_HDR_SG_MOD_OFF) +/* dw6 */ +#define CMD_HDR_DIF_SGL_LEN_OFF0 +#define CMD_HDR_DIF_SGL_LEN_MSK(0x << CMD_HDR_DIF_SGL_LEN_OFF) +#define CMD_HDR_DATA_SGL_LEN_OFF 16 +#define CMD_HDR_DATA_SGL_LEN_MSK (0x << CMD_HDR_DATA_SGL_LEN_OFF) + /* Completion header */ /* dw0 */ #define CMPLT_HDR_CMPLT_OFF0 @@ -201,6 +236,11 @@ enum { HISI_SAS_PHY_INT_NR }; +#define DIR_NO_DATA 0 +#define DIR_TO_INI 1 +#define DIR_TO_DEVICE 2 +#define DIR_RESERVED 3 + static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { void __iomem *regs = hisi_hba->regs + off; @@ -208,6 +248,13 @@ static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) return readl(regs); } +static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off) +{ + void __iomem *regs = hisi_hba->regs + off; + + return readl_relaxed(regs); +} + static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val) { void __iomem *regs = hisi_hba->regs + off; @@ -432,6 +479,163 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control); } +/** + * The callpath to this function and upto writing the write + * queue pointer should be safe from interruption. + */ +static int +get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq) +{ + struct device *dev = hisi_hba->dev; + int queue = dq->id; + u32 r, w; + + w = dq->wr_point; + r = hisi_sas_read32_relaxed(hisi_hba, + DLVRY_Q_0_RD_PTR + (queue * 0x14)); + if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { + dev_warn(dev, "full queue=%d r=%d w=%d\n\n", + queue, r, w); + return -EAGAIN; + } + + return 0; +} + +static void start_delivery_v3_hw(struct hisi_sas_dq *dq) +{ + struct hisi_hba *hisi_hba = dq->hisi_hba; + int dlvry_queue = dq->slot_prep->dlvry_queue; + int dlvry_queue_slot = dq->slot_prep->dlvry_queue_slot; + + dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS; + hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), +dq->wr_point); +} + +static int prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot, + struct hisi_sas_cmd_hdr *hdr, + struct scatterlist *scatter, + int n_elem) +{ + struct device *dev = hisi_hba->dev; + struct scatterlist *sg; + int i; + + if (n_elem > HISI_SAS_SGE_PAGE_CNT) { + dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT", + n_elem); +
[PATCH v3 16/23] scsi: hisi_sas: add v3 code to send SMP frame
From: Xiang ChenAdd code to prepare SMP frame. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 74 ++ 1 file changed, 74 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 7be3a53..d4e4844 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -186,6 +186,9 @@ #define CMD_HDR_MRFL_MSK (0x1ff << CMD_HDR_MRFL_OFF) #define CMD_HDR_SG_MOD_OFF 24 #define CMD_HDR_SG_MOD_MSK (0x3 << CMD_HDR_SG_MOD_OFF) +/* dw3 */ +#define CMD_HDR_IPTT_OFF 0 +#define CMD_HDR_IPTT_MSK (0x << CMD_HDR_IPTT_OFF) /* dw6 */ #define CMD_HDR_DIF_SGL_LEN_OFF0 #define CMD_HDR_DIF_SGL_LEN_MSK(0x << CMD_HDR_DIF_SGL_LEN_OFF) @@ -636,6 +639,76 @@ static int prep_ssp_v3_hw(struct hisi_hba *hisi_hba, return 0; } +static int prep_smp_v3_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot) +{ + struct sas_task *task = slot->task; + struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; + struct domain_device *device = task->dev; + struct device *dev = hisi_hba->dev; + struct hisi_sas_port *port = slot->port; + struct scatterlist *sg_req, *sg_resp; + struct hisi_sas_device *sas_dev = device->lldd_dev; + dma_addr_t req_dma_addr; + unsigned int req_len, resp_len; + int elem, rc; + + /* +* DMA-map SMP request, response buffers +*/ + /* req */ + sg_req = >smp_task.smp_req; + elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE); + if (!elem) + return -ENOMEM; + req_len = sg_dma_len(sg_req); + req_dma_addr = sg_dma_address(sg_req); + + /* resp */ + sg_resp = >smp_task.smp_resp; + elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE); + if (!elem) { + rc = -ENOMEM; + goto err_out_req; + } + resp_len = sg_dma_len(sg_resp); + if ((req_len & 0x3) || (resp_len & 0x3)) { + rc = -EINVAL; + goto err_out_resp; + } + + /* create header */ + /* dw0 */ + hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) | + (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */ + (2 << CMD_HDR_CMD_OFF)); /* smp */ + + /* map itct entry */ + hdr->dw1 = cpu_to_le32((sas_dev->device_id << CMD_HDR_DEV_ID_OFF) | + (1 << CMD_HDR_FRAME_TYPE_OFF) | + (DIR_NO_DATA << CMD_HDR_DIR_OFF)); + + /* dw2 */ + hdr->dw2 = cpu_to_le32req_len - 4) / 4) << CMD_HDR_CFL_OFF) | + (HISI_SAS_MAX_SMP_RESP_SZ / 4 << + CMD_HDR_MRFL_OFF)); + + hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF); + + hdr->cmd_table_addr = cpu_to_le64(req_dma_addr); + hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma); + + return 0; + +err_out_resp: + dma_unmap_sg(dev, >task->smp_task.smp_resp, 1, +DMA_FROM_DEVICE); +err_out_req: + dma_unmap_sg(dev, >task->smp_task.smp_req, 1, +DMA_TO_DEVICE); + return rc; +} + static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) { int i, res = 0; @@ -1230,6 +1303,7 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba) .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr), .sl_notify = sl_notify_v3_hw, .prep_ssp = prep_ssp_v3_hw, + .prep_smp = prep_smp_v3_hw, .get_free_slot = get_free_slot_v3_hw, .start_delivery = start_delivery_v3_hw, .slot_complete = slot_complete_v3_hw, -- 1.9.1
[PATCH v3 11/23] scsi: hisi_sas: add v3 hw init
From: Xiang ChenAdd code to initialise v3 hardware. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 277 + 1 file changed, 277 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 3e74225..da74ed8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -11,7 +11,283 @@ #include "hisi_sas.h" #define DRV_NAME "hisi_sas_v3_hw" +/* global registers need init*/ +#define DLVRY_QUEUE_ENABLE 0x0 +#define IOST_BASE_ADDR_LO 0x8 +#define IOST_BASE_ADDR_HI 0xc +#define ITCT_BASE_ADDR_LO 0x10 +#define ITCT_BASE_ADDR_HI 0x14 +#define IO_BROKEN_MSG_ADDR_LO 0x18 +#define IO_BROKEN_MSG_ADDR_HI 0x1c +#define AXI_AHB_CLK_CFG0x3c +#define AXI_USER1 0x48 +#define AXI_USER2 0x4c +#define IO_SATA_BROKEN_MSG_ADDR_LO 0x58 +#define IO_SATA_BROKEN_MSG_ADDR_HI 0x5c +#define SATA_INITI_D2H_STORE_ADDR_LO 0x60 +#define SATA_INITI_D2H_STORE_ADDR_HI 0x64 +#define CFG_MAX_TAG0x68 +#define HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL0x84 +#define HGC_SAS_TXFAIL_RETRY_CTRL 0x88 +#define HGC_GET_ITV_TIME 0x90 +#define DEVICE_MSG_WORK_MODE 0x94 +#define OPENA_WT_CONTI_TIME0x9c +#define I_T_NEXUS_LOSS_TIME0xa0 +#define MAX_CON_TIME_LIMIT_TIME0xa4 +#define BUS_INACTIVE_LIMIT_TIME0xa8 +#define REJECT_TO_OPEN_LIMIT_TIME 0xac +#define CFG_AGING_TIME 0xbc +#define HGC_DFX_CFG2 0xc0 +#define CFG_ABT_SET_QUERY_IPTT 0xd4 +#define CFG_SET_ABORTED_IPTT_OFF 0 +#define CFG_SET_ABORTED_IPTT_MSK (0xfff << CFG_SET_ABORTED_IPTT_OFF) +#define CFG_1US_TIMER_TRSH 0xcc +#define INT_COAL_EN0x19c +#define OQ_INT_COAL_TIME 0x1a0 +#define OQ_INT_COAL_CNT0x1a4 +#define ENT_INT_COAL_TIME 0x1a8 +#define ENT_INT_COAL_CNT 0x1ac +#define OQ_INT_SRC 0x1b0 +#define OQ_INT_SRC_MSK 0x1b4 +#define ENT_INT_SRC1 0x1b8 +#define ENT_INT_SRC1_D2H_FIS_CH0_OFF 0 +#define ENT_INT_SRC1_D2H_FIS_CH0_MSK (0x1 << ENT_INT_SRC1_D2H_FIS_CH0_OFF) +#define ENT_INT_SRC1_D2H_FIS_CH1_OFF 8 +#define ENT_INT_SRC1_D2H_FIS_CH1_MSK (0x1 << ENT_INT_SRC1_D2H_FIS_CH1_OFF) +#define ENT_INT_SRC2 0x1bc +#define ENT_INT_SRC3 0x1c0 +#define ENT_INT_SRC3_WP_DEPTH_OFF 8 +#define ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF 9 +#define ENT_INT_SRC3_RP_DEPTH_OFF 10 +#define ENT_INT_SRC3_AXI_OFF 11 +#define ENT_INT_SRC3_FIFO_OFF 12 +#define ENT_INT_SRC3_LM_OFF14 +#define ENT_INT_SRC3_ITC_INT_OFF 15 +#define ENT_INT_SRC3_ITC_INT_MSK (0x1 << ENT_INT_SRC3_ITC_INT_OFF) +#define ENT_INT_SRC3_ABT_OFF 16 +#define ENT_INT_SRC_MSK1 0x1c4 +#define ENT_INT_SRC_MSK2 0x1c8 +#define ENT_INT_SRC_MSK3 0x1cc +#define CHNL_PHYUPDOWN_INT_MSK 0x1d0 +#define CHNL_ENT_INT_MSK 0x1d4 +#define HGC_COM_INT_MSK0x1d8 +#define SAS_ECC_INTR 0x1e8 +#define SAS_ECC_INTR_MSK 0x1ec +#define HGC_ERR_STAT_EN0x238 +#define DLVRY_Q_0_BASE_ADDR_LO 0x260 +#define DLVRY_Q_0_BASE_ADDR_HI 0x264 +#define DLVRY_Q_0_DEPTH0x268 +#define DLVRY_Q_0_WR_PTR 0x26c +#define DLVRY_Q_0_RD_PTR 0x270 +#define HYPER_STREAM_ID_EN_CFG 0xc80 +#define OQ0_INT_SRC_MSK0xc90 +#define COMPL_Q_0_BASE_ADDR_LO 0x4e0 +#define COMPL_Q_0_BASE_ADDR_HI 0x4e4 +#define COMPL_Q_0_DEPTH0x4e8 +#define COMPL_Q_0_WR_PTR 0x4ec +#define COMPL_Q_0_RD_PTR 0x4f0 +#define AWQOS_AWCACHE_CFG 0xc84 +#define ARQOS_ARCACHE_CFG 0xc88 + +/* phy registers requiring init */ +#define PORT_BASE (0x2000) +#define PROG_PHY_LINK_RATE (PORT_BASE + 0x8) +#define PHY_CTRL (PORT_BASE + 0x14) +#define PHY_CTRL_RESET_OFF 0 +#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF) +#define SL_CFG (PORT_BASE + 0x84) +#define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc) +#define SAS_SSP_CON_TIMER_CFG (PORT_BASE + 0x134) +#define SAS_SMP_CON_TIMER_CFG (PORT_BASE + 0x138) +#define SAS_STP_CON_TIMER_CFG (PORT_BASE + 0x13c) +#define CHL_INT0 (PORT_BASE + 0x1b4) +#define
[PATCH v3 10/23] scsi: hisi_sas: add initialisation for v3 pci-based controller
Add the code to initialise the controller which is based on pci device in hisi_sas_v3_hw.c The core controller routines are still in hisi_sas_main.c; some common initialisation functions are also exported from hisi_sas_main.c For pci-based controller, the device properties, like phy count and sas address are read from the firmware, same as platform device-based controller. Signed-off-by: John GarrySigned-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas.h | 6 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 18 ++-- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 155 + 3 files changed, 173 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 480f9ae..5fe5a55 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -360,6 +360,12 @@ struct hisi_sas_command_table_ssp { struct hisi_sas_command_table_stp stp; }; +extern struct scsi_transport_template *hisi_sas_stt; +extern struct scsi_host_template *hisi_sas_sht; + +extern void hisi_sas_init_add(struct hisi_hba *hisi_hba); +extern int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost); +extern void hisi_sas_free(struct hisi_hba *hisi_hba); extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction); extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); extern void hisi_sas_sata_done(struct sas_task *task, diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 5979ab6..f5a73bd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1478,9 +1478,10 @@ void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, } EXPORT_SYMBOL_GPL(hisi_sas_rescan_topology); -static struct scsi_transport_template *hisi_sas_stt; +struct scsi_transport_template *hisi_sas_stt; +EXPORT_SYMBOL_GPL(hisi_sas_stt); -static struct scsi_host_template hisi_sas_sht = { +static struct scsi_host_template _hisi_sas_sht = { .module = THIS_MODULE, .name = DRV_NAME, .queuecommand = sas_queuecommand, @@ -1500,6 +1501,8 @@ void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, }; +struct scsi_host_template *hisi_sas_sht = &_hisi_sas_sht; +EXPORT_SYMBOL_GPL(hisi_sas_sht); static struct sas_domain_function_template hisi_sas_transport_ops = { .lldd_dev_found = hisi_sas_dev_found, @@ -1547,7 +1550,7 @@ void hisi_sas_init_mem(struct hisi_hba *hisi_hba) } EXPORT_SYMBOL_GPL(hisi_sas_init_mem); -static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) +int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) { struct device *dev = hisi_hba->dev; int i, s, max_command_entries = hisi_hba->hw->max_command_entries; @@ -1666,8 +1669,9 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) err_out: return -ENOMEM; } +EXPORT_SYMBOL_GPL(hisi_sas_alloc); -static void hisi_sas_free(struct hisi_hba *hisi_hba) +void hisi_sas_free(struct hisi_hba *hisi_hba) { struct device *dev = hisi_hba->dev; int i, s, max_command_entries = hisi_hba->hw->max_command_entries; @@ -1722,6 +1726,7 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba) if (hisi_hba->wq) destroy_workqueue(hisi_hba->wq); } +EXPORT_SYMBOL_GPL(hisi_sas_free); static void hisi_sas_rst_work_handler(struct work_struct *work) { @@ -1807,7 +1812,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, struct hisi_hba *hisi_hba; struct device *dev = >dev; - shost = scsi_host_alloc(_sas_sht, sizeof(*hisi_hba)); + shost = scsi_host_alloc(hisi_sas_sht, sizeof(*hisi_hba)); if (!shost) { dev_err(dev, "scsi host alloc failed\n"); return NULL; @@ -1849,7 +1854,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, return NULL; } -static void hisi_sas_init_add(struct hisi_hba *hisi_hba) +void hisi_sas_init_add(struct hisi_hba *hisi_hba) { int i; @@ -1858,6 +1863,7 @@ static void hisi_sas_init_add(struct hisi_hba *hisi_hba) hisi_hba->sas_addr, SAS_ADDR_SIZE); } +EXPORT_SYMBOL_GPL(hisi_sas_init_add); int hisi_sas_probe(struct platform_device *pdev, const struct hisi_sas_hw *hw) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index cf72577..3e74225 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -11,14 +11,169 @@ #include "hisi_sas.h" #define DRV_NAME "hisi_sas_v3_hw" +static const
[PATCH v3 17/23] scsi: hisi_sas: add v3 code to send ATA frame
From: Xiang ChenAdd code to prepare ATA frame for v3 hw Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 106 + 1 file changed, 106 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index d4e4844..613c625 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -171,8 +171,11 @@ #define CMD_HDR_CMD_OFF29 #define CMD_HDR_CMD_MSK(0x7 << CMD_HDR_CMD_OFF) /* dw1 */ +#define CMD_HDR_UNCON_CMD_OFF 3 #define CMD_HDR_DIR_OFF5 #define CMD_HDR_DIR_MSK(0x3 << CMD_HDR_DIR_OFF) +#define CMD_HDR_RESET_OFF 7 +#define CMD_HDR_RESET_MSK (0x1 << CMD_HDR_RESET_OFF) #define CMD_HDR_VDTL_OFF 10 #define CMD_HDR_VDTL_MSK (0x1 << CMD_HDR_VDTL_OFF) #define CMD_HDR_FRAME_TYPE_OFF 11 @@ -182,6 +185,8 @@ /* dw2 */ #define CMD_HDR_CFL_OFF0 #define CMD_HDR_CFL_MSK(0x1ff << CMD_HDR_CFL_OFF) +#define CMD_HDR_NCQ_TAG_OFF10 +#define CMD_HDR_NCQ_TAG_MSK(0x1f << CMD_HDR_NCQ_TAG_OFF) #define CMD_HDR_MRFL_OFF 15 #define CMD_HDR_MRFL_MSK (0x1ff << CMD_HDR_MRFL_OFF) #define CMD_HDR_SG_MOD_OFF 24 @@ -244,6 +249,11 @@ enum { #define DIR_TO_DEVICE 2 #define DIR_RESERVED 3 +#define CMD_IS_UNCONSTRAINT(cmd) \ + ((cmd == ATA_CMD_READ_LOG_EXT) || \ + (cmd == ATA_CMD_READ_LOG_DMA_EXT) || \ + (cmd == ATA_CMD_DEV_RESET)) + static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { void __iomem *regs = hisi_hba->regs + off; @@ -709,6 +719,101 @@ static int prep_smp_v3_hw(struct hisi_hba *hisi_hba, return rc; } +static int get_ncq_tag_v3_hw(struct sas_task *task, u32 *tag) +{ + struct ata_queued_cmd *qc = task->uldd_task; + + if (qc) { + if (qc->tf.command == ATA_CMD_FPDMA_WRITE || + qc->tf.command == ATA_CMD_FPDMA_READ) { + *tag = qc->tag; + return 1; + } + } + return 0; +} + +static int prep_ata_v3_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot) +{ + struct sas_task *task = slot->task; + struct domain_device *device = task->dev; + struct domain_device *parent_dev = device->parent; + struct hisi_sas_device *sas_dev = device->lldd_dev; + struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); + u8 *buf_cmd; + int has_data = 0, rc = 0, hdr_tag = 0; + u32 dw1 = 0, dw2 = 0; + + hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF); + if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF); + else + hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF); + + switch (task->data_dir) { + case DMA_TO_DEVICE: + has_data = 1; + dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF; + break; + case DMA_FROM_DEVICE: + has_data = 1; + dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF; + break; + default: + dw1 &= ~CMD_HDR_DIR_MSK; + } + + if ((task->ata_task.fis.command == ATA_CMD_DEV_RESET) && + (task->ata_task.fis.control & ATA_SRST)) + dw1 |= 1 << CMD_HDR_RESET_OFF; + + dw1 |= (hisi_sas_get_ata_protocol( + task->ata_task.fis.command, task->data_dir)) + << CMD_HDR_FRAME_TYPE_OFF; + dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; + + if (CMD_IS_UNCONSTRAINT(task->ata_task.fis.command)) + dw1 |= 1 << CMD_HDR_UNCON_CMD_OFF; + + hdr->dw1 = cpu_to_le32(dw1); + + /* dw2 */ + if (task->ata_task.use_ncq && get_ncq_tag_v3_hw(task, _tag)) { + task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); + dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF; + } + + dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / 4) << CMD_HDR_CFL_OFF | + 2 << CMD_HDR_SG_MOD_OFF; + hdr->dw2 = cpu_to_le32(dw2); + + /* dw3 */ + hdr->transfer_tags = cpu_to_le32(slot->idx); + + if (has_data) { + rc = prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter, + slot->n_elem); + if (rc) + return rc; + } + + hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len); + hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma); +
[PATCH v3 13/23] scsi: hisi_sas: add phy up/down/bcast and channel ISR
From: Xiang ChenAdd code to initialise interrupts and add some interrupt handlers. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 281 + 1 file changed, 281 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 9651658..49f14d2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -173,6 +173,13 @@ enum { HISI_SAS_PHY_INT_NR }; +static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) +{ + void __iomem *regs = hisi_hba->regs + off; + + return readl(regs); +} + static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val) { void __iomem *regs = hisi_hba->regs + off; @@ -397,6 +404,276 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control); } +static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) +{ + int i, res = 0; + u32 context, port_id, link_rate, hard_phy_linkrate; + struct hisi_sas_phy *phy = _hba->phy[phy_no]; + struct asd_sas_phy *sas_phy = >sas_phy; + struct device *dev = hisi_hba->dev; + + hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); + + port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA); + port_id = (port_id >> (4 * phy_no)) & 0xf; + link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE); + link_rate = (link_rate >> (phy_no * 4)) & 0xf; + + if (port_id == 0xf) { + dev_err(dev, "phyup: phy%d invalid portid\n", phy_no); + res = IRQ_NONE; + goto end; + } + sas_phy->linkrate = link_rate; + hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no, + HARD_PHY_LINKRATE); + phy->maximum_linkrate = hard_phy_linkrate & 0xf; + phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf; + phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); + + /* Check for SATA dev */ + context = hisi_sas_read32(hisi_hba, PHY_CONTEXT); + if (context & (1 << phy_no)) { + struct hisi_sas_initial_fis *initial_fis; + struct dev_to_host_fis *fis; + u8 attached_sas_addr[SAS_ADDR_SIZE] = {0}; + + dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); + initial_fis = _hba->initial_fis[phy_no]; + fis = _fis->fis; + sas_phy->oob_mode = SATA_OOB_MODE; + attached_sas_addr[0] = 0x50; + attached_sas_addr[7] = phy_no; + memcpy(sas_phy->attached_sas_addr, + attached_sas_addr, + SAS_ADDR_SIZE); + memcpy(sas_phy->frame_rcvd, fis, + sizeof(struct dev_to_host_fis)); + phy->phy_type |= PORT_TYPE_SATA; + phy->identify.device_type = SAS_SATA_DEV; + phy->frame_rcvd_size = sizeof(struct dev_to_host_fis); + phy->identify.target_port_protocols = SAS_PROTOCOL_SATA; + } else { + u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd; + struct sas_identify_frame *id = + (struct sas_identify_frame *)frame_rcvd; + + dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); + for (i = 0; i < 6; i++) { + u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no, + RX_IDAF_DWORD0 + (i * 4)); + frame_rcvd[i] = __swab32(idaf); + } + sas_phy->oob_mode = SAS_OOB_MODE; + memcpy(sas_phy->attached_sas_addr, + >sas_addr, + SAS_ADDR_SIZE); + phy->phy_type |= PORT_TYPE_SAS; + phy->identify.device_type = id->dev_type; + phy->frame_rcvd_size = sizeof(struct sas_identify_frame); + if (phy->identify.device_type == SAS_END_DEVICE) + phy->identify.target_port_protocols = + SAS_PROTOCOL_SSP; + else if (phy->identify.device_type != SAS_PHY_UNUSED) + phy->identify.target_port_protocols = + SAS_PROTOCOL_SMP; + } + + phy->port_id = port_id; + phy->phy_attached = 1; + queue_work(hisi_hba->wq, >phyup_ws); + +end: + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, +CHL_INT0_SL_PHY_ENABLE_MSK); + hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0); + + return res; +} + +static int phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba) +{ + int res = 0; + u32 phy_state,
[PATCH v3 12/23] scsi: hisi_sas: add v3 hw PHY init
From: Xiang ChenAdd code to configure PHYs for v3 hw. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 127 - 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index da74ed8..9651658 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -19,6 +19,10 @@ #define ITCT_BASE_ADDR_HI 0x14 #define IO_BROKEN_MSG_ADDR_LO 0x18 #define IO_BROKEN_MSG_ADDR_HI 0x1c +#define PHY_CONTEXT0x20 +#define PHY_STATE 0x24 +#define PHY_PORT_NUM_MA0x28 +#define PHY_CONN_RATE 0x30 #define AXI_AHB_CLK_CFG0x3c #define AXI_USER1 0x48 #define AXI_USER2 0x4c @@ -42,6 +46,7 @@ #define CFG_SET_ABORTED_IPTT_OFF 0 #define CFG_SET_ABORTED_IPTT_MSK (0xfff << CFG_SET_ABORTED_IPTT_OFF) #define CFG_1US_TIMER_TRSH 0xcc +#define CHNL_INT_STATUS0x148 #define INT_COAL_EN0x19c #define OQ_INT_COAL_TIME 0x1a0 #define OQ_INT_COAL_CNT0x1a4 @@ -68,9 +73,11 @@ #define ENT_INT_SRC_MSK1 0x1c4 #define ENT_INT_SRC_MSK2 0x1c8 #define ENT_INT_SRC_MSK3 0x1cc +#define ENT_INT_SRC_MSK3_ENT95_MSK_OFF 31 #define CHNL_PHYUPDOWN_INT_MSK 0x1d0 #define CHNL_ENT_INT_MSK 0x1d4 #define HGC_COM_INT_MSK0x1d8 +#define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF) #define SAS_ECC_INTR 0x1e8 #define SAS_ECC_INTR_MSK 0x1ec #define HGC_ERR_STAT_EN0x238 @@ -91,11 +98,33 @@ /* phy registers requiring init */ #define PORT_BASE (0x2000) +#define PHY_CFG(PORT_BASE + 0x0) +#define HARD_PHY_LINKRATE (PORT_BASE + 0x4) +#define PHY_CFG_ENA_OFF0 +#define PHY_CFG_ENA_MSK(0x1 << PHY_CFG_ENA_OFF) +#define PHY_CFG_DC_OPT_OFF 2 +#define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF) #define PROG_PHY_LINK_RATE (PORT_BASE + 0x8) #define PHY_CTRL (PORT_BASE + 0x14) #define PHY_CTRL_RESET_OFF 0 #define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF) #define SL_CFG (PORT_BASE + 0x84) +#define SL_CONTROL (PORT_BASE + 0x94) +#define SL_CONTROL_NOTIFY_EN_OFF 0 +#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF) +#define SL_CTA_OFF 17 +#define SL_CTA_MSK (0x1 << SL_CTA_OFF) +#define TX_ID_DWORD0 (PORT_BASE + 0x9c) +#define TX_ID_DWORD1 (PORT_BASE + 0xa0) +#define TX_ID_DWORD2 (PORT_BASE + 0xa4) +#define TX_ID_DWORD3 (PORT_BASE + 0xa8) +#define TX_ID_DWORD4 (PORT_BASE + 0xaC) +#define TX_ID_DWORD5 (PORT_BASE + 0xb0) +#define TX_ID_DWORD6 (PORT_BASE + 0xb4) +#define TXID_AUTO (PORT_BASE + 0xb8) +#define CT3_OFF1 +#define CT3_MSK(0x1 << CT3_OFF) +#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4) #define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc) #define SAS_SSP_CON_TIMER_CFG (PORT_BASE + 0x134) #define SAS_SMP_CON_TIMER_CFG (PORT_BASE + 0x138) @@ -136,6 +165,13 @@ struct hisi_sas_complete_v3_hdr { }; #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096 +#define HISI_SAS_MSI_COUNT_V3_HW 32 + +enum { + HISI_SAS_PHY_PHY_UPDOWN, + HISI_SAS_PHY_CHNL_INT, + HISI_SAS_PHY_INT_NR +}; static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val) { @@ -152,6 +188,14 @@ static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba, int phy_no, writel(val, regs); } +static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba, + int phy_no, u32 off) +{ + void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off; + + return readl(regs); +} + static void init_reg_v3_hw(struct hisi_hba *hisi_hba) { int i; @@ -266,6 +310,45 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) upper_32_bits(hisi_hba->initial_fis_dma)); } +static void config_phy_opt_mode_v3_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); + + cfg &= ~PHY_CFG_DC_OPT_MSK; + cfg |= 1 << PHY_CFG_DC_OPT_OFF; + hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); +} +
[PATCH v3 20/23] scsi: hisi_sas: add get_wideport_bitmap_v3_hw()
From: Xiang ChenAdd code for interface get_wideport_bitmap. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 7bb9d2a..f71f1ba 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -613,6 +613,18 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control); } +static int get_wideport_bitmap_v3_hw(struct hisi_hba *hisi_hba, int port_id) +{ + int i, bitmap = 0; + u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA); + + for (i = 0; i < hisi_hba->n_phy; i++) + if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id) + bitmap |= 1 << i; + + return bitmap; +} + /** * The callpath to this function and upto writing the write * queue pointer should be safe from interruption. @@ -1555,6 +1567,7 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba) .hw_init = hisi_sas_v3_init, .setup_itct = setup_itct_v3_hw, .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW, + .get_wideport_bitmap = get_wideport_bitmap_v3_hw, .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr), .free_device = free_device_v3_hw, .sl_notify = sl_notify_v3_hw, @@ -1730,6 +1743,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) pci_disable_device(pdev); } + enum { /* instances of the controller */ hip08, -- 1.9.1
[PATCH v3 14/23] scsi: hisi_sas: add v3 cq interrupt handler
From: Xiang ChenAdd v3 cq interrupt handler slot_complete_v2_hw(). Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 32 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 331 + 3 files changed, 364 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 5fe5a55..d7545ff 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -372,6 +372,7 @@ extern void hisi_sas_sata_done(struct sas_task *task, struct hisi_sas_slot *slot); extern int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag); extern int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba); +extern bool hisi_sas_is_rw_cmd(struct sas_task *task); extern int hisi_sas_probe(struct platform_device *pdev, const struct hisi_sas_hw *ops); extern int hisi_sas_remove(struct platform_device *pdev); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f5a73bd..b90eb50 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -118,6 +118,38 @@ int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag) } EXPORT_SYMBOL_GPL(hisi_sas_get_ncq_tag); +bool hisi_sas_is_rw_cmd(struct sas_task *task) +{ + switch (task->task_proto) { + case SAS_PROTOCOL_SSP: + { + unsigned char op = task->ssp_task.cmd->cmnd[0]; + + if (op == READ_6 || op == WRITE_6 || + op == READ_10 || op == WRITE_10 || + op == READ_12 || op == WRITE_12 || + op == READ_16 || op == WRITE_16) + return true; + break; + } + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + { + u32 cmd_proto = hisi_sas_get_ata_protocol( + task->ata_task.fis.command, + task->data_dir); + if (cmd_proto != SATA_PROTOCOL_NONDATA) + return true; + break; + } + default: + break; + } + return false; +} +EXPORT_SYMBOL_GPL(hisi_sas_is_rw_cmd); + static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) { return device->port->ha->lldd_ha; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 49f14d2..4259047 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -157,6 +157,32 @@ #define SL_RX_BCAST_CHK_MSK(PORT_BASE + 0x2c0) #define PHYCTRL_OOB_RESTART_MSK(PORT_BASE + 0x2c4) +/* Completion header */ +/* dw0 */ +#define CMPLT_HDR_CMPLT_OFF0 +#define CMPLT_HDR_CMPLT_MSK(0x3 << CMPLT_HDR_CMPLT_OFF) +#define CMPLT_HDR_ERROR_PHASE_OFF 2 +#define CMPLT_HDR_ERROR_PHASE_MSK (0xff << CMPLT_HDR_ERROR_PHASE_OFF) +#define CMPLT_HDR_RSPNS_XFRD_OFF 10 +#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF) +#define CMPLT_HDR_ERX_OFF 12 +#define CMPLT_HDR_ERX_MSK (0x1 << CMPLT_HDR_ERX_OFF) +#define CMPLT_HDR_ABORT_STAT_OFF 13 +#define CMPLT_HDR_ABORT_STAT_MSK (0x7 << CMPLT_HDR_ABORT_STAT_OFF) +/* abort_stat */ +#define STAT_IO_NOT_VALID 0x1 +#define STAT_IO_NO_DEVICE 0x2 +#define STAT_IO_COMPLETE 0x3 +#define STAT_IO_ABORTED0x4 +/* dw1 */ +#define CMPLT_HDR_IPTT_OFF 0 +#define CMPLT_HDR_IPTT_MSK (0x << CMPLT_HDR_IPTT_OFF) +#define CMPLT_HDR_DEV_ID_OFF 16 +#define CMPLT_HDR_DEV_ID_MSK (0x << CMPLT_HDR_DEV_ID_OFF) +/* dw3 */ +#define CMPLT_HDR_IO_IN_TARGET_OFF 17 +#define CMPLT_HDR_IO_IN_TARGET_MSK (0x1 << CMPLT_HDR_IO_IN_TARGET_OFF) + struct hisi_sas_complete_v3_hdr { __le32 dw0; __le32 dw1; @@ -164,6 +190,8 @@ struct hisi_sas_complete_v3_hdr { __le32 dw3; }; +#define IO_RX_DATA_LEN_UNDERFLOW_OFF 6 +#define IO_RX_DATA_LEN_UNDERFLOW_MSK (1 << IO_RX_DATA_LEN_UNDERFLOW_OFF) #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096 #define HISI_SAS_MSI_COUNT_V3_HW 32 @@ -625,6 +653,286 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p) return IRQ_HANDLED; } +static void slot_err_v3_hw(struct hisi_hba *hisi_hba, + struct sas_task *task, + struct hisi_sas_slot *slot) +{ + struct task_status_struct *ts = >task_status; + struct hisi_sas_complete_v3_hdr *complete_queue = + hisi_hba->complete_hdr[slot->cmplt_queue]; + struct hisi_sas_complete_v3_hdr *complete_hdr
[PATCH v3 19/23] scsi: hisi_sas: add v3 code to send internal abort command
From: Xiang ChenAdd code to prepare internal abort command. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 38 ++ 1 file changed, 38 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 720abd1c..7bb9d2a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -165,6 +165,10 @@ /* HW dma structures */ /* Delivery queue header */ /* dw0 */ +#define CMD_HDR_ABORT_FLAG_OFF 0 +#define CMD_HDR_ABORT_FLAG_MSK (0x3 << CMD_HDR_ABORT_FLAG_OFF) +#define CMD_HDR_ABORT_DEVICE_TYPE_OFF 2 +#define CMD_HDR_ABORT_DEVICE_TYPE_MSK (0x1 << CMD_HDR_ABORT_DEVICE_TYPE_OFF) #define CMD_HDR_RESP_REPORT_OFF5 #define CMD_HDR_RESP_REPORT_MSK(0x1 << CMD_HDR_RESP_REPORT_OFF) #define CMD_HDR_TLR_CTRL_OFF 6 @@ -204,6 +208,11 @@ #define CMD_HDR_DIF_SGL_LEN_MSK(0x << CMD_HDR_DIF_SGL_LEN_OFF) #define CMD_HDR_DATA_SGL_LEN_OFF 16 #define CMD_HDR_DATA_SGL_LEN_MSK (0x << CMD_HDR_DATA_SGL_LEN_OFF) +/* dw7 */ +#define CMD_HDR_ADDR_MODE_SEL_OFF 15 +#define CMD_HDR_ADDR_MODE_SEL_MSK (1 << CMD_HDR_ADDR_MODE_SEL_OFF) +#define CMD_HDR_ABORT_IPTT_OFF 16 +#define CMD_HDR_ABORT_IPTT_MSK (0x << CMD_HDR_ABORT_IPTT_OFF) /* Completion header */ /* dw0 */ @@ -926,6 +935,34 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba, return 0; } +static int prep_abort_v3_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot, + int device_id, int abort_flag, int tag_to_abort) +{ + struct sas_task *task = slot->task; + struct domain_device *dev = task->dev; + struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; + struct hisi_sas_port *port = slot->port; + + /* dw0 */ + hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/ + (port->id << CMD_HDR_PORT_OFF) | + ((dev_is_sata(dev) ? 1:0) + << CMD_HDR_ABORT_DEVICE_TYPE_OFF) | + (abort_flag +<< CMD_HDR_ABORT_FLAG_OFF)); + + /* dw1 */ + hdr->dw1 = cpu_to_le32(device_id + << CMD_HDR_DEV_ID_OFF); + + /* dw7 */ + hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF); + hdr->transfer_tags = cpu_to_le32(slot->idx); + + return 0; +} + static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) { int i, res = 0; @@ -1524,6 +1561,7 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba) .prep_ssp = prep_ssp_v3_hw, .prep_smp = prep_smp_v3_hw, .prep_stp = prep_ata_v3_hw, + .prep_abort = prep_abort_v3_hw, .get_free_slot = get_free_slot_v3_hw, .start_delivery = start_delivery_v3_hw, .slot_complete = slot_complete_v3_hw, -- 1.9.1
[PATCH v3 22/23] scsi: hisi_sas: add v3 code to fill some more hw function pointers
From: Xiang ChenAdd code to fill the interface of phy_hard_reset, phy_get_max_linkrate, and phy enable/disable. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 40 +- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 3203221..17f9ac9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -195,6 +195,8 @@ #define TXID_AUTO (PORT_BASE + 0xb8) #define CT3_OFF1 #define CT3_MSK(0x1 << CT3_OFF) +#define TX_HARDRST_OFF 2 +#define TX_HARDRST_MSK (0x1 << TX_HARDRST_OFF) #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4) #define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc) #define SAS_SSP_CON_TIMER_CFG (PORT_BASE + 0x134) @@ -648,6 +650,14 @@ static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); } +static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); + + cfg &= ~PHY_CFG_ENA_MSK; + hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); +} + static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) { config_id_frame_v3_hw(hisi_hba, phy_no); @@ -655,6 +665,11 @@ static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) enable_phy_v3_hw(hisi_hba, phy_no); } +static void stop_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + disable_phy_v3_hw(hisi_hba, phy_no); +} + static void start_phys_v3_hw(struct hisi_hba *hisi_hba) { int i; @@ -663,6 +678,26 @@ static void start_phys_v3_hw(struct hisi_hba *hisi_hba) start_phy_v3_hw(hisi_hba, i); } +static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + struct hisi_sas_phy *phy = _hba->phy[phy_no]; + u32 txid_auto; + + stop_phy_v3_hw(hisi_hba, phy_no); + if (phy->identify.device_type == SAS_END_DEVICE) { + txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); + hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, + txid_auto | TX_HARDRST_MSK); + } + msleep(100); + start_phy_v3_hw(hisi_hba, phy_no); +} + +enum sas_linkrate phy_get_max_linkrate_v3_hw(void) +{ + return SAS_LINK_RATE_12_0_GBPS; +} + static void phys_init_v3_hw(struct hisi_hba *hisi_hba) { start_phys_v3_hw(hisi_hba); @@ -1977,6 +2012,10 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba) .start_delivery = start_delivery_v3_hw, .slot_complete = slot_complete_v3_hw, .phys_init = phys_init_v3_hw, + .phy_enable = enable_phy_v3_hw, + .phy_disable = disable_phy_v3_hw, + .phy_hard_reset = phy_hard_reset_v3_hw, + .phy_get_max_linkrate = phy_get_max_linkrate_v3_hw, }; static struct Scsi_Host * @@ -2141,7 +2180,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) pci_disable_device(pdev); } - enum { /* instances of the controller */ hip08, -- 1.9.1
[PATCH v3 00/23] hisi_sas: hip08 support
This patchset adds support for the HiSilicon SAS controller in the hip08 chipset. The key difference compared to earlier chipsets is that the controller is an integrated PCI endpoint in hip08. As such, the controller is a pci device (not a platform device, like v2 hw in hip07). The driver is refactored so it can support both platform and pci device-based controllers. New hw layer file hisi_sas_v3_hw.c is added for v3 hw support, which also includes pci device proving and initialisation. Common functionality is still in hisi_sas_main.c, along with platform device probing and initialization. As for the patches, (ignoring #1-3) the first few reorganise some functions from v2 hw.c into main.c, as they are required for v3 hw. Then support is added for pci device-based controller in subsequent patches. And then hip08 support is added in the final patches. Differences to v2 series: - Add patch to change hisi_sas_device.device_id size - Add device dq pointer - Remove hisi_sas_v3_hw prototype in v3 driver - Add explicit comment in hisi_sas_get_fw_info() Differences to v1 series: - Addressed Arnd's comments, including: - read sas address from device node DSD under PCI host bridge - add comment in fatal axi error patch commit log regarding controller reset - eliminate hisi_sas_pci_init.c, and move functionality into hisi_sas_v3_hw.c, eliminating one layer of indirection John Garry (5): scsi: hisi_sas: define hisi_sas_device.device_id as int scsi: hisi_sas: add pci_dev in hisi_hba struct scsi: hisi_sas: create hisi_sas_get_fw_info() scsi: hisi_sas: add skeleton v3 hw driver scsi: hisi_sas: add initialisation for v3 pci-based controller Xiang Chen (18): scsi: hisi_sas: fix timeout check in hisi_sas_internal_task_abort() scsi: hisi_sas: optimise the usage of hisi_hba.lock scsi: hisi_sas: relocate get_ata_protocol() scsi: hisi_sas: relocate sata_done_v2_hw() scsi: hisi_sas: relocate get_ncq_tag_v2_hw() scsi: hisi_sas: add v3 hw init scsi: hisi_sas: add v3 hw PHY init scsi: hisi_sas: add phy up/down/bcast and channel ISR scsi: hisi_sas: add v3 cq interrupt handler scsi: hisi_sas: add v3 code to send SSP frame scsi: hisi_sas: add v3 code to send SMP frame scsi: hisi_sas: add v3 code to send ATA frame scsi: hisi_sas: add v3 code for itct setup and free scsi: hisi_sas: add v3 code to send internal abort command scsi: hisi_sas: add get_wideport_bitmap_v3_hw() scsi: hisi_sas: Add v3 code to support ECC and AXI bus fatal error scsi: hisi_sas: add v3 code to fill some more hw function pointers scsi: hisi_sas: modify internal abort dev flow for v3 hw drivers/scsi/hisi_sas/Kconfig | 10 +- drivers/scsi/hisi_sas/Makefile |1 + drivers/scsi/hisi_sas/hisi_sas.h | 37 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 393 -- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 51 +- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 179 +-- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2234 7 files changed, 2640 insertions(+), 265 deletions(-) create mode 100644 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c -- 1.9.1
[PATCH V2 12/15] qedf: Move some prints to a debug level so they do not print when no debugging is enabled.
Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_main.c | 13 - 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 45c741b..4b688d6 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -442,7 +442,8 @@ static void qedf_link_update(void *dev, struct qed_link_output *link) qedf_update_link_speed(qedf, link); if (atomic_read(>dcbx) == QEDF_DCBX_DONE) { - QEDF_ERR(&(qedf->dbg_ctx), "DCBx done.\n"); + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, +"DCBx done.\n"); if (atomic_read(>link_down_tmo_valid) > 0) queue_delayed_work(qedf->link_update_wq, >link_recovery, 0); @@ -2155,14 +2156,15 @@ static void qedf_recv_frame(struct qedf_ctx *qedf, } if (ntoh24(_mac[3]) != ntoh24(fh->fh_d_id)) { - QEDF_ERR(&(qedf->dbg_ctx), "FC frame d_id mismatch with MAC %pM.\n", - dest_mac); + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, + "FC frame d_id mismatch with MAC %pM.\n", dest_mac); return; } if (qedf->ctlr.state) { if (!ether_addr_equal(mac, qedf->ctlr.dest_addr)) { - QEDF_ERR(&(qedf->dbg_ctx), "Wrong source address mac:%pM dest_addr:%pM.\n", + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, + "Wrong source address: mac:%pM dest_addr:%pM.\n", mac, qedf->ctlr.dest_addr); kfree_skb(skb); return; @@ -2177,7 +2179,8 @@ static void qedf_recv_frame(struct qedf_ctx *qedf, * empty then this is not addressed to our port so simply drop it. */ if (lport->port_id != ntoh24(fh->fh_d_id) && !vn_port) { - QEDF_ERR(&(qedf->dbg_ctx), "Dropping frame due to destination mismatch: lport->port_id=%x fh->d_id=%x.\n", + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, + "Dropping frame due to destination mismatch: lport->port_id=%x fh->d_id=%x.\n", lport->port_id, ntoh24(fh->fh_d_id)); kfree_skb(skb); return; -- 1.8.5.6
[PATCH V2 14/15] qedf: Add change_queue_depth member to scsi_host_template().
Add the change_queue_depth member to our SCSI host template so the queue depth of devices attached to qedf can be changed dynamically. Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 27a9e26..ff32865 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -722,6 +722,7 @@ static int qedf_slave_configure(struct scsi_device *sdev) .dma_boundary = QED_HW_DMA_BOUNDARY, .sg_tablesize = QEDF_MAX_BDS_PER_CMD, .can_queue = FCOE_PARAMS_NUM_TASKS, + .change_queue_depth = scsi_change_queue_depth, }; static int qedf_get_paged_crc_eof(struct sk_buff *skb, int tlen) -- 1.8.5.6
[PATCH V2 15/15] qedf: Update version number to 8.18.22.0.
Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qedf/qedf_version.h b/drivers/scsi/qedf/qedf_version.h index d46c487..6fa4420 100644 --- a/drivers/scsi/qedf/qedf_version.h +++ b/drivers/scsi/qedf/qedf_version.h @@ -7,9 +7,9 @@ * this source tree. */ -#define QEDF_VERSION "8.10.7.0" +#define QEDF_VERSION "8.18.22.0" #define QEDF_DRIVER_MAJOR_VER 8 -#define QEDF_DRIVER_MINOR_VER 10 -#define QEDF_DRIVER_REV_VER7 +#define QEDF_DRIVER_MINOR_VER 18 +#define QEDF_DRIVER_REV_VER22 #define QEDF_DRIVER_ENG_VER0 -- 1.8.5.6
[PATCH V2 13/15] qedf: Change cmd_per_lun in scsi_host_template to 32 to increase performance.
Increase the default number of commands that the driver tells the SCSI mid-layer it can do to increase the default performance of the driver. Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 4b688d6..27a9e26 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -708,7 +708,7 @@ static int qedf_slave_configure(struct scsi_device *sdev) .module = THIS_MODULE, .name = QEDF_MODULE_NAME, .this_id= -1, - .cmd_per_lun= 3, + .cmd_per_lun= 32, .use_clustering = ENABLE_CLUSTERING, .max_sectors= 0x, .queuecommand = qedf_queuecommand, -- 1.8.5.6
[PATCH V2 10/15] qedf: Add non-offload receive filters.
Drop invalid or unexpected FCoE frames that come into the non-offload path since the FCoE firmware would not do the filtering for us. Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_main.c | 43 +++ 1 file changed, 43 insertions(+) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index d762b9f..45c741b 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2087,6 +2087,8 @@ static void qedf_recv_frame(struct qedf_ctx *qedf, u8 *dest_mac = NULL; struct fcoe_hdr *hp; struct qedf_rport *fcport; + struct fc_lport *vn_port; + u32 f_ctl; lport = qedf->lport; if (lport == NULL || lport->state == LPORT_ST_DISABLED) { @@ -2123,6 +2125,10 @@ static void qedf_recv_frame(struct qedf_ctx *qedf, fh = fc_frame_header_get(fp); + /* +* Invalid frame filters. +*/ + if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP) { /* Drop FCP data. We dont this in L2 path */ @@ -2148,6 +2154,43 @@ static void qedf_recv_frame(struct qedf_ctx *qedf, return; } + if (ntoh24(_mac[3]) != ntoh24(fh->fh_d_id)) { + QEDF_ERR(&(qedf->dbg_ctx), "FC frame d_id mismatch with MAC %pM.\n", + dest_mac); + return; + } + + if (qedf->ctlr.state) { + if (!ether_addr_equal(mac, qedf->ctlr.dest_addr)) { + QEDF_ERR(&(qedf->dbg_ctx), "Wrong source address mac:%pM dest_addr:%pM.\n", + mac, qedf->ctlr.dest_addr); + kfree_skb(skb); + return; + } + } + + vn_port = fc_vport_id_lookup(lport, ntoh24(fh->fh_d_id)); + + /* +* If the destination ID from the frame header does not match what we +* have on record for lport and the search for a NPIV port came up +* empty then this is not addressed to our port so simply drop it. +*/ + if (lport->port_id != ntoh24(fh->fh_d_id) && !vn_port) { + QEDF_ERR(&(qedf->dbg_ctx), "Dropping frame due to destination mismatch: lport->port_id=%x fh->d_id=%x.\n", + lport->port_id, ntoh24(fh->fh_d_id)); + kfree_skb(skb); + return; + } + + f_ctl = ntoh24(fh->fh_f_ctl); + if ((fh->fh_type == FC_TYPE_BLS) && (f_ctl & FC_FC_SEQ_CTX) && + (f_ctl & FC_FC_EX_CTX)) { + /* Drop incoming ABTS response that has both SEQ/EX CTX set */ + kfree_skb(skb); + return; + } + /* * If a connection is uploading, drop incoming FCoE frames as there * is a small window where we could try to return a frame while libfc -- 1.8.5.6
[PATCH V2 08/15] qedf: Use same logic for SCSI host reset and FC lip_reset.
We should be using the same logic to do a soft reset of the FCoE function whether it is initiated via sg_reset or the fc_host issue_lip attribute. Refactor the host reset and fcoe reset handlers to use the preferred logic which is currently contained in qedf_eh_host_reset(). Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_main.c | 39 +++ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index d08793e..99d8822 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -640,27 +640,17 @@ void qedf_wait_for_upload(struct qedf_ctx *qedf) } } -/* Reset the host by gracefully logging out and then logging back in */ -static int qedf_eh_host_reset(struct scsi_cmnd *sc_cmd) +/* Performs soft reset of qedf_ctx by simulating a link down/up */ +static void qedf_ctx_soft_reset(struct fc_lport *lport) { - struct fc_lport *lport; struct qedf_ctx *qedf; - lport = shost_priv(sc_cmd->device->host); - if (lport->vport) { QEDF_ERR(NULL, "Cannot issue host reset on NPIV port.\n"); - return SUCCESS; + return; } - qedf = (struct qedf_ctx *)lport_priv(lport); - - if (atomic_read(>link_state) == QEDF_LINK_DOWN || - test_bit(QEDF_UNLOADING, >flags) || - test_bit(QEDF_DBG_STOP_IO, >flags)) - return FAILED; - - QEDF_ERR(&(qedf->dbg_ctx), "HOST RESET Issued..."); + qedf = lport_priv(lport); /* For host reset, essentially do a soft link up/down */ atomic_set(>link_state, QEDF_LINK_DOWN); @@ -672,6 +662,24 @@ static int qedf_eh_host_reset(struct scsi_cmnd *sc_cmd) qedf->vlan_id = 0; queue_delayed_work(qedf->link_update_wq, >link_update, 0); +} + +/* Reset the host by gracefully logging out and then logging back in */ +static int qedf_eh_host_reset(struct scsi_cmnd *sc_cmd) +{ + struct fc_lport *lport; + struct qedf_ctx *qedf; + + lport = shost_priv(sc_cmd->device->host); + qedf = lport_priv(lport); + + if (atomic_read(>link_state) == QEDF_LINK_DOWN || + test_bit(QEDF_UNLOADING, >flags)) + return FAILED; + + QEDF_ERR(&(qedf->dbg_ctx), "HOST RESET Issued..."); + + qedf_ctx_soft_reset(lport); return SUCCESS; } @@ -1669,8 +1677,7 @@ static int qedf_fcoe_reset(struct Scsi_Host *shost) { struct fc_lport *lport = shost_priv(shost); - fc_fabric_logoff(lport); - fc_fabric_login(lport); + qedf_ctx_soft_reset(lport); return 0; } -- 1.8.5.6
[PATCH V2 05/15] qedf: Check that fcport is offloaded before dereferencing pointers in initiate_abts|cleanup.
If an fcport is not offloaded then the members of the qedf_rport struct are undefined which may cause a system crash. Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_io.c | 22 -- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index ca9097b..db16004 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -1476,8 +1476,8 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) { struct fc_lport *lport; struct qedf_rport *fcport = io_req->fcport; - struct fc_rport_priv *rdata = fcport->rdata; - struct qedf_ctx *qedf = fcport->qedf; + struct fc_rport_priv *rdata; + struct qedf_ctx *qedf; u16 xid; u32 r_a_tov = 0; int rc = 0; @@ -1485,15 +1485,18 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) struct fcoe_wqe *sqe; u16 sqe_idx; - r_a_tov = rdata->r_a_tov; - lport = qedf->lport; - + /* Sanity check qedf_rport before dereferencing any pointers */ if (!test_bit(QEDF_RPORT_SESSION_READY, >flags)) { - QEDF_ERR(&(qedf->dbg_ctx), "tgt not offloaded\n"); + QEDF_ERR(NULL, "tgt not offloaded\n"); rc = 1; goto abts_err; } + rdata = fcport->rdata; + r_a_tov = rdata->r_a_tov; + qedf = fcport->qedf; + lport = qedf->lport; + if (lport->state != LPORT_ST_READY || !(lport->link_up)) { QEDF_ERR(&(qedf->dbg_ctx), "link is not ready\n"); rc = 1; @@ -1729,6 +1732,13 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, return SUCCESS; } + /* Sanity check qedf_rport before dereferencing any pointers */ + if (!test_bit(QEDF_RPORT_SESSION_READY, >flags)) { + QEDF_ERR(NULL, "tgt not offloaded\n"); + rc = 1; + return SUCCESS; + } + qedf = fcport->qedf; if (!qedf) { QEDF_ERR(NULL, "qedf is NULL.\n"); -- 1.8.5.6
[PATCH V2 09/15] qedf: Add bus_reset No-op.
We need to add a bus reset no-op as without it some of the LUNs attached to a vport may go offline when the error handler escalates to host reset due to not having a bus reset handler in the driver. What happens is we escalate to host reset which does a soft link down/link up to reset the adapter. However with multiple vports attached it's been observed that if the vports do log back into the target within 5 seconds, the SCSI layer offlines the devices most likely due to a TUR timing out to verify that the device is online. Adding a bus reset handler will cause the TUR to be sent after the bus reset handler where the devices will still be online if the bus reset is initiated by sg_reset (which is the case in the test that was failing). The bus reset will succeed and not needlessly bring the device offline/online. Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_main.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 99d8822..d762b9f 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -628,6 +628,16 @@ static int qedf_eh_device_reset(struct scsi_cmnd *sc_cmd) return qedf_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); } +static int qedf_eh_bus_reset(struct scsi_cmnd *sc_cmd) +{ + QEDF_ERR(NULL, "BUS RESET Issued...\n"); + /* +* Essentially a no-op but return SUCCESS to prevent +* unnecessary escalation to the host reset handler. +*/ + return SUCCESS; +} + void qedf_wait_for_upload(struct qedf_ctx *qedf) { while (1) { @@ -705,6 +715,7 @@ static int qedf_slave_configure(struct scsi_device *sdev) .eh_abort_handler = qedf_eh_abort, .eh_device_reset_handler = qedf_eh_device_reset, /* lun reset */ .eh_target_reset_handler = qedf_eh_target_reset, /* target reset */ + .eh_bus_reset_handler = qedf_eh_bus_reset, .eh_host_reset_handler = qedf_eh_host_reset, .slave_configure= qedf_slave_configure, .dma_boundary = QED_HW_DMA_BOUNDARY, -- 1.8.5.6
[PATCH V2 06/15] qedf: Add fka_period SCSI host attribute to show fip keep alive period.
Expose this information for interested applications. Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_attr.c | 57 --- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/qedf/qedf_attr.c b/drivers/scsi/qedf/qedf_attr.c index 1349f8a..fa67276 100644 --- a/drivers/scsi/qedf/qedf_attr.c +++ b/drivers/scsi/qedf/qedf_attr.c @@ -8,6 +8,25 @@ */ #include "qedf.h" +inline bool qedf_is_vport(struct qedf_ctx *qedf) +{ + return qedf->lport->vport != NULL; +} + +/* Get base qedf for physical port from vport */ +static struct qedf_ctx *qedf_get_base_qedf(struct qedf_ctx *qedf) +{ + struct fc_lport *lport; + struct fc_lport *base_lport; + + if (!(qedf_is_vport(qedf))) + return NULL; + + lport = qedf->lport; + base_lport = shost_priv(vport_to_shost(lport->vport)); + return lport_priv(base_lport); +} + static ssize_t qedf_fcoe_mac_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -26,34 +45,34 @@ return scnprintf(buf, PAGE_SIZE, "%pM\n", fcoe_mac); } +static ssize_t +qedf_fka_period_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fc_lport *lport = shost_priv(class_to_shost(dev)); + struct qedf_ctx *qedf = lport_priv(lport); + int fka_period = -1; + + if (qedf_is_vport(qedf)) + qedf = qedf_get_base_qedf(qedf); + + if (qedf->ctlr.sel_fcf) + fka_period = qedf->ctlr.sel_fcf->fka_period; + + return scnprintf(buf, PAGE_SIZE, "%d\n", fka_period); +} + static DEVICE_ATTR(fcoe_mac, S_IRUGO, qedf_fcoe_mac_show, NULL); +static DEVICE_ATTR(fka_period, S_IRUGO, qedf_fka_period_show, NULL); struct device_attribute *qedf_host_attrs[] = { _attr_fcoe_mac, + _attr_fka_period, NULL, }; extern const struct qed_fcoe_ops *qed_ops; -inline bool qedf_is_vport(struct qedf_ctx *qedf) -{ - return (!(qedf->lport->vport == NULL)); -} - -/* Get base qedf for physical port from vport */ -static struct qedf_ctx *qedf_get_base_qedf(struct qedf_ctx *qedf) -{ - struct fc_lport *lport; - struct fc_lport *base_lport; - - if (!(qedf_is_vport(qedf))) - return NULL; - - lport = qedf->lport; - base_lport = shost_priv(vport_to_shost(lport->vport)); - return (struct qedf_ctx *)(lport_priv(base_lport)); -} - void qedf_capture_grc_dump(struct qedf_ctx *qedf) { struct qedf_ctx *base_qedf; -- 1.8.5.6
[PATCH V2 11/15] qedf: Fixup unnecessary parantheses around test_bit operations.
Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_els.c | 6 +++--- drivers/scsi/qedf/qedf_io.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c index e197fd6..78d9f1c 100644 --- a/drivers/scsi/qedf/qedf_els.c +++ b/drivers/scsi/qedf/qedf_els.c @@ -44,7 +44,7 @@ static int qedf_initiate_els(struct qedf_rport *fcport, unsigned int op, goto els_err; } - if (!(test_bit(QEDF_RPORT_SESSION_READY, >flags))) { + if (!test_bit(QEDF_RPORT_SESSION_READY, >flags)) { QEDF_ERR(&(qedf->dbg_ctx), "els 0x%x: fcport not ready\n", op); rc = -EINVAL; goto els_err; @@ -225,7 +225,7 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req) fcport = aborted_io_req->fcport; /* Check that fcport is still offloaded */ - if (!(test_bit(QEDF_RPORT_SESSION_READY, >flags))) { + if (!test_bit(QEDF_RPORT_SESSION_READY, >flags)) { QEDF_ERR(NULL, "fcport is no longer offloaded.\n"); return -EINVAL; } @@ -550,7 +550,7 @@ static int qedf_send_srr(struct qedf_ioreq *orig_io_req, u32 offset, u8 r_ctl) fcport = orig_io_req->fcport; /* Check that fcport is still offloaded */ - if (!(test_bit(QEDF_RPORT_SESSION_READY, >flags))) { + if (!test_bit(QEDF_RPORT_SESSION_READY, >flags)) { QEDF_ERR(NULL, "fcport is no longer offloaded.\n"); return -EINVAL; } diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index db16004..ea37c78 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -1847,7 +1847,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, return FAILED; } - if (!(test_bit(QEDF_RPORT_SESSION_READY, >flags))) { + if (!test_bit(QEDF_RPORT_SESSION_READY, >flags)) { QEDF_ERR(&(qedf->dbg_ctx), "fcport not offloaded\n"); rc = FAILED; return FAILED; -- 1.8.5.6
[PATCH V2 04/15] qedf: Look at all descriptors when processing a clear virtual link.
If there are multiple descriptors for a particular type in a clear virtual link we receive, we will not process it correctly but rather take the last value. This can cause us not to not flap the virtual link as the value from the descriptors that we compare against the our stored FCF or fc_lport values may not match. Change this to do a comparison when processing the each descriptor instead of at the end and then set a bool if we need to do the reset. Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_fip.c | 20 +--- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/qedf/qedf_fip.c b/drivers/scsi/qedf/qedf_fip.c index 2dfb817..64b04f2 100644 --- a/drivers/scsi/qedf/qedf_fip.c +++ b/drivers/scsi/qedf/qedf_fip.c @@ -156,10 +156,9 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) struct fip_wwn_desc *wp; struct fip_vn_desc *vp; size_t rlen, dlen; - uint32_t cvl_port_id; - __u8 cvl_mac[ETH_ALEN]; u16 op; u8 sub; + bool do_reset = false; eth_hdr = (struct ethhdr *)skb_mac_header(skb); fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2); @@ -190,8 +189,6 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) return; } - cvl_port_id = 0; - memset(cvl_mac, 0, ETH_ALEN); /* * We need to loop through the CVL descriptors to determine * if we want to reset the fcoe link @@ -205,7 +202,9 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) mp = (struct fip_mac_desc *)desc; QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "fd_mac=%pM\n", mp->fd_mac); - ether_addr_copy(cvl_mac, mp->fd_mac); + if (ether_addr_equal(mp->fd_mac, + qedf->ctlr.sel_fcf->fcf_mac)) + do_reset = true; break; case FIP_DT_NAME: wp = (struct fip_wwn_desc *)desc; @@ -217,7 +216,9 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) vp = (struct fip_vn_desc *)desc; QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "fd_fc_id=%x.\n", ntoh24(vp->fd_fc_id)); - cvl_port_id = ntoh24(vp->fd_fc_id); + if (ntoh24(vp->fd_fc_id) == + qedf->lport->port_id) + do_reset = true; break; default: /* Ignore anything else */ @@ -228,11 +229,8 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) } QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "cvl_port_id=%06x cvl_mac=%pM.\n", cvl_port_id, - cvl_mac); - if (cvl_port_id == qedf->lport->port_id && - ether_addr_equal(cvl_mac, - qedf->ctlr.sel_fcf->fcf_mac)) { + "do_reset=%d.\n", do_reset); + if (do_reset) { fcoe_ctlr_link_down(>ctlr); qedf_wait_for_upload(qedf); fcoe_ctlr_link_up(>ctlr); -- 1.8.5.6
[PATCH V2 03/15] qedf: Honor qed_ops->common->set_fp_int() return code.
We need to check the return code the set_fp_int() callback in case we were not allocated any fastpath interrupts or there was an error setting up the fastpath interrupts from the qed perspective. Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 9457665..884103b 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2035,6 +2035,8 @@ static int qedf_setup_int(struct qedf_ctx *qedf) * Learn interrupt configuration */ rc = qed_ops->common->set_fp_int(qedf->cdev, num_online_cpus()); + if (rc <= 0) + return 0; rc = qed_ops->common->get_fp_int(qedf->cdev, >int_info); if (rc) -- 1.8.5.6
[PATCH V2 00/15] qedf: Update driver to version 8.18.22.0.
Hi Martin, Please apply the following patches to the scsi tree at your earliest convenience. Thanks, Chad Change from V1 -> V2: - Use fc_host attributes directly instead of using fc_host_* macros when setting FDMI attributes - Fix typos in patch descriptions - Implement suggested code refactoring for fka_period sysfs attribute - Keep newly introduced error message strings on one line Dupuis, Chad (15): qedf: Enable basic FDMI information. qedf: Update copyright to 2017. qedf: Honor qed_ops->common->set_fp_int() return code. qedf: Look at all descriptors when processing a clear virtual link. qedf: Check that fcport is offloaded before dereferencing pointers in initiate_abts|cleanup. qedf: Add fka_period SCSI host attribute to show fip keep alive period. qedf: Set qed logging level to QED_LEVEL_NOTICE. qedf: Use same logic for SCSI host reset and FC lip_reset. qedf: Add bus_reset No-op. qedf: Add non-offload receive filters. qedf: Fixup unnecessary parantheses around test_bit operations. qedf: Move some prints to a debug level so they do not print when no debugging is enabled. qedf: Change cmd_per_lun in scsi_host_template to 32 to increase performance. qedf: Add change_queue_depth member to scsi_host_template(). qedf: Update version number to 8.18.22.0. drivers/scsi/qedf/drv_fcoe_fw_funcs.c | 2 +- drivers/scsi/qedf/drv_fcoe_fw_funcs.h | 2 +- drivers/scsi/qedf/drv_scsi_fw_funcs.c | 2 +- drivers/scsi/qedf/drv_scsi_fw_funcs.h | 2 +- drivers/scsi/qedf/qedf.h | 2 +- drivers/scsi/qedf/qedf_attr.c | 59 +++- drivers/scsi/qedf/qedf_dbg.h | 2 +- drivers/scsi/qedf/qedf_debugfs.c | 2 +- drivers/scsi/qedf/qedf_els.c | 8 +- drivers/scsi/qedf/qedf_fip.c | 22 +++-- drivers/scsi/qedf/qedf_hsi.h | 2 +- drivers/scsi/qedf/qedf_io.c | 26 -- drivers/scsi/qedf/qedf_main.c | 163 +- drivers/scsi/qedf/qedf_version.h | 8 +- 14 files changed, 226 insertions(+), 76 deletions(-) -- 1.8.5.6
[PATCH V2 07/15] qedf: Set qed logging level to QED_LEVEL_NOTICE.
Reduce the logging level we set for qed messages pertaining to this PCI function so that unnecessary messages are not printed in the kernel message log. Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 884103b..d08793e 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -95,7 +95,7 @@ MODULE_PARM_DESC(dp_module, " bit flags control for verbose printk passed " "qed module during probe."); -static uint qedf_dp_level; +static uint qedf_dp_level = QED_LEVEL_NOTICE; module_param_named(dp_level, qedf_dp_level, uint, S_IRUGO); MODULE_PARM_DESC(dp_level, " printk verbosity control passed to qed module " "during probe (0-3: 0 more verbose)."); -- 1.8.5.6
[PATCH V2 01/15] qedf: Enable basic FDMI information.
For libfc to register FDMI attributes we need to do two things: - Set the appropriate fc_host attributes that libfc will use to form the FDMI registration commands - Set lport->fdmi_enabled to 1 Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/qedf_main.c | 56 +++ 1 file changed, 56 insertions(+) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index cceddd9..8d0a999 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -22,6 +22,7 @@ #include #include #include "qedf.h" +#include const struct qed_fcoe_ops *qed_ops; @@ -1334,6 +1335,59 @@ static void qedf_fcoe_ctlr_setup(struct qedf_ctx *qedf) ether_addr_copy(qedf->ctlr.ctl_src_addr, qedf->mac); } +static void qedf_setup_fdmi(struct qedf_ctx *qedf) +{ + struct fc_lport *lport = qedf->lport; + struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host); + u8 buf[8]; + int i, pos; + + /* +* fdmi_enabled needs to be set for libfc to execute FDMI registration. +*/ + lport->fdmi_enabled = 1; + + /* +* Setup the necessary fc_host attributes to that will be used to fill +* in the FDMI information. +*/ + + /* Get the PCI-e Device Serial Number Capability */ + pos = pci_find_ext_capability(qedf->pdev, PCI_EXT_CAP_ID_DSN); + if (pos) { + pos += 4; + for (i = 0; i < 8; i++) + pci_read_config_byte(qedf->pdev, pos + i, [i]); + + snprintf(fc_host->serial_number, + sizeof(fc_host->serial_number), + "%02X%02X%02X%02X%02X%02X%02X%02X", + buf[7], buf[6], buf[5], buf[4], + buf[3], buf[2], buf[1], buf[0]); + } else + snprintf(fc_host->serial_number, + sizeof(fc_host->serial_number), "Unknown"); + + snprintf(fc_host->manufacturer, + sizeof(fc_host->manufacturer), "%s", "Cavium Inc."); + + snprintf(fc_host->model, sizeof(fc_host->model), "%s", "QL41000"); + + snprintf(fc_host->model_description, sizeof(fc_host->model_description), + "%s", "QLogic FastLinQ QL41000 Series 10/25/40/50GGbE Controller" + "(FCoE)"); + + snprintf(fc_host->hardware_version, sizeof(fc_host->hardware_version), + "Rev %d", qedf->pdev->revision); + + snprintf(fc_host->driver_version, sizeof(fc_host->driver_version), + "%s", QEDF_VERSION); + + snprintf(fc_host->firmware_version, sizeof(fc_host->firmware_version), + "%d.%d.%d.%d", FW_MAJOR_VERSION, FW_MINOR_VERSION, + FW_REVISION_VERSION, FW_ENGINEERING_VERSION); +} + static int qedf_lport_setup(struct qedf_ctx *qedf) { struct fc_lport *lport = qedf->lport; @@ -1377,6 +1431,8 @@ static int qedf_lport_setup(struct qedf_ctx *qedf) snprintf(fc_host_symbolic_name(lport->host), 256, "QLogic %s v%s", QEDF_MODULE_NAME, QEDF_VERSION); + qedf_setup_fdmi(qedf); + return 0; } -- 1.8.5.6
[PATCH V2 02/15] qedf: Update copyright to 2017.
Signed-off-by: Chad Dupuis--- drivers/scsi/qedf/drv_fcoe_fw_funcs.c | 2 +- drivers/scsi/qedf/drv_fcoe_fw_funcs.h | 2 +- drivers/scsi/qedf/drv_scsi_fw_funcs.c | 2 +- drivers/scsi/qedf/drv_scsi_fw_funcs.h | 2 +- drivers/scsi/qedf/qedf.h | 2 +- drivers/scsi/qedf/qedf_attr.c | 2 +- drivers/scsi/qedf/qedf_dbg.h | 2 +- drivers/scsi/qedf/qedf_debugfs.c | 2 +- drivers/scsi/qedf/qedf_els.c | 2 +- drivers/scsi/qedf/qedf_fip.c | 2 +- drivers/scsi/qedf/qedf_hsi.h | 2 +- drivers/scsi/qedf/qedf_io.c | 2 +- drivers/scsi/qedf/qedf_main.c | 2 +- drivers/scsi/qedf/qedf_version.h | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/qedf/drv_fcoe_fw_funcs.c b/drivers/scsi/qedf/drv_fcoe_fw_funcs.c index 8c65e3b..7d91e53 100644 --- a/drivers/scsi/qedf/drv_fcoe_fw_funcs.c +++ b/drivers/scsi/qedf/drv_fcoe_fw_funcs.c @@ -1,5 +1,5 @@ /* QLogic FCoE Offload Driver - * Copyright (c) 2016 Cavium Inc. + * Copyright (c) 2016-2017 Cavium Inc. * * This software is available under the terms of the GNU General Public License * (GPL) Version 2, available from the file COPYING in the main directory of diff --git a/drivers/scsi/qedf/drv_fcoe_fw_funcs.h b/drivers/scsi/qedf/drv_fcoe_fw_funcs.h index 617529b..f9c50fa 100644 --- a/drivers/scsi/qedf/drv_fcoe_fw_funcs.h +++ b/drivers/scsi/qedf/drv_fcoe_fw_funcs.h @@ -1,5 +1,5 @@ /* QLogic FCoE Offload Driver - * Copyright (c) 2016 Cavium Inc. + * Copyright (c) 2016-2017 Cavium Inc. * * This software is available under the terms of the GNU General Public License * (GPL) Version 2, available from the file COPYING in the main directory of diff --git a/drivers/scsi/qedf/drv_scsi_fw_funcs.c b/drivers/scsi/qedf/drv_scsi_fw_funcs.c index 11e0cc0..5d5095e 100644 --- a/drivers/scsi/qedf/drv_scsi_fw_funcs.c +++ b/drivers/scsi/qedf/drv_scsi_fw_funcs.c @@ -1,5 +1,5 @@ /* QLogic FCoE Offload Driver - * Copyright (c) 2016 Cavium Inc. + * Copyright (c) 2016-2017 Cavium Inc. * * This software is available under the terms of the GNU General Public License * (GPL) Version 2, available from the file COPYING in the main directory of diff --git a/drivers/scsi/qedf/drv_scsi_fw_funcs.h b/drivers/scsi/qedf/drv_scsi_fw_funcs.h index 9cb4541..8fbe6e4 100644 --- a/drivers/scsi/qedf/drv_scsi_fw_funcs.h +++ b/drivers/scsi/qedf/drv_scsi_fw_funcs.h @@ -1,5 +1,5 @@ /* QLogic FCoE Offload Driver - * Copyright (c) 2016 Cavium Inc. + * Copyright (c) 2016-2017 Cavium Inc. * * This software is available under the terms of the GNU General Public License * (GPL) Version 2, available from the file COPYING in the main directory of diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h index 40aeb6b..a5b89b0 100644 --- a/drivers/scsi/qedf/qedf.h +++ b/drivers/scsi/qedf/qedf.h @@ -1,6 +1,6 @@ /* * QLogic FCoE Offload Driver - * Copyright (c) 2016 Cavium Inc. + * Copyright (c) 2016-2017 Cavium Inc. * * This software is available under the terms of the GNU General Public License * (GPL) Version 2, available from the file COPYING in the main directory of diff --git a/drivers/scsi/qedf/qedf_attr.c b/drivers/scsi/qedf/qedf_attr.c index 4772061..1349f8a 100644 --- a/drivers/scsi/qedf/qedf_attr.c +++ b/drivers/scsi/qedf/qedf_attr.c @@ -1,6 +1,6 @@ /* * QLogic FCoE Offload Driver - * Copyright (c) 2016 Cavium Inc. + * Copyright (c) 2016-2017 Cavium Inc. * * This software is available under the terms of the GNU General Public License * (GPL) Version 2, available from the file COPYING in the main directory of diff --git a/drivers/scsi/qedf/qedf_dbg.h b/drivers/scsi/qedf/qedf_dbg.h index 7d173f48..50083ca 100644 --- a/drivers/scsi/qedf/qedf_dbg.h +++ b/drivers/scsi/qedf/qedf_dbg.h @@ -1,6 +1,6 @@ /* * QLogic FCoE Offload Driver - * Copyright (c) 2016 Cavium Inc. + * Copyright (c) 2016-2017 Cavium Inc. * * This software is available under the terms of the GNU General Public License * (GPL) Version 2, available from the file COPYING in the main directory of diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index 00a1d64..2b1ef30 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -1,6 +1,6 @@ /* * QLogic FCoE Offload Driver - * Copyright (c) 2016 QLogic Corporation + * Copyright (c) 2016-2017 QLogic Corporation * * This software is available under the terms of the GNU General Public License * (GPL) Version 2, available from the file COPYING in the main directory of diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c index c505d41..e197fd6 100644 --- a/drivers/scsi/qedf/qedf_els.c +++ b/drivers/scsi/qedf/qedf_els.c @@ -1,6 +1,6 @@ /* * QLogic FCoE Offload Driver - * Copyright (c) 2016 Cavium Inc. + * Copyright (c) 2016-2017 Cavium Inc. * * This software is available under the terms of the GNU General
[PATCH v3 3/9] blk-mq: use the introduced blk_mq_unquiesce_queue()
blk_mq_unquiesce_queue() is used for unquiescing the queue explicitly, so replace blk_mq_start_stopped_hw_queues() with it. Cc: linux-n...@lists.infradead.org Cc: linux-scsi@vger.kernel.org Cc: dm-de...@redhat.com Signed-off-by: Ming Lei--- drivers/md/dm-rq.c | 2 +- drivers/nvme/host/core.c | 2 +- drivers/scsi/scsi_lib.c | 5 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index b639fa7246ee..ea4029de077f 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -71,7 +71,7 @@ static void dm_old_start_queue(struct request_queue *q) static void dm_mq_start_queue(struct request_queue *q) { - blk_mq_start_stopped_hw_queues(q, true); + blk_mq_unquiesce_queue(q); blk_mq_kick_requeue_list(q); } diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index a60926410438..c3f189e54d10 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2526,7 +2526,7 @@ void nvme_start_queues(struct nvme_ctrl *ctrl) mutex_lock(>namespaces_mutex); list_for_each_entry(ns, >namespaces, list) { - blk_mq_start_stopped_hw_queues(ns->queue, true); + blk_mq_unquiesce_queue(ns->queue); blk_mq_kick_requeue_list(ns->queue); } mutex_unlock(>namespaces_mutex); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 99e16ac479e3..ffcf05765e2b 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3031,7 +3031,10 @@ scsi_internal_device_unblock(struct scsi_device *sdev, return -EINVAL; if (q->mq_ops) { - blk_mq_start_stopped_hw_queues(q, false); + if (blk_queue_quiesced(q)) + blk_mq_unquiesce_queue(q); + else + blk_mq_start_stopped_hw_queues(q, false); } else { spin_lock_irqsave(q->queue_lock, flags); blk_start_queue(q); -- 2.9.4
RE: [PATCH] megaraid: Fix a sleep-in-atomic bug
>-Original Message- >From: Jia-Ju Bai [mailto:baijiaju1...@163.com] >Sent: Wednesday, May 31, 2017 8:27 AM >To: kashyap.de...@broadcom.com; sumit.sax...@broadcom.com; >shivasharan.srikanteshw...@broadcom.com; j...@linux.vnet.ibm.com; >martin.peter...@oracle.com >Cc: megaraidlinux@broadcom.com; linux-scsi@vger.kernel.org; linux- >ker...@vger.kernel.org; Jia-Ju Bai >Subject: [PATCH] megaraid: Fix a sleep-in-atomic bug > >The driver may sleep under a spin lock, and the function call path is: >mraid_mm_attach_buf (acquire the lock by spin_lock_irqsave) > pci_pool_alloc(GFP_KERNEL) --> may sleep > >To fix it, the "GFP_KERNEL" is replaced with "GFP_ATOMIC". > >Signed-off-by: Jia-Ju Bai>--- > drivers/scsi/megaraid/megaraid_mm.c |2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/drivers/scsi/megaraid/megaraid_mm.c >b/drivers/scsi/megaraid/megaraid_mm.c >index 4cf9ed9..c43afb8 100644 >--- a/drivers/scsi/megaraid/megaraid_mm.c >+++ b/drivers/scsi/megaraid/megaraid_mm.c >@@ -574,7 +574,7 @@ > > kioc->pool_index= right_pool; > kioc->free_buf = 1; >- kioc->buf_vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, >+ kioc->buf_vaddr = pci_pool_alloc(pool->handle, GFP_ATOMIC, > >buf_paddr); > spin_unlock_irqrestore(>lock, flags); This is very old driver and reached EOL. Did you face any issue because of this bug or discover this through code review? Anyways patch looks good to me. Acked-by: Sumit Saxena > >-- >1.7.9.5 >
Re: [PATCH 0/3] libfc: fix potential timer list corruption
On 05/30/2017 05:14 PM, Hannes Reinecke wrote: > Hi all, > > we've seen reports for a crash with an invalid timer_list->function, > which turned out to be an unsafe usage of libfc discovery callbacks. > This patchset fixes up the problem > > As usual, comments and reviews are welcome. The patches look good themselves, but I'd prefer a *why* in the commit message. For instance in patch 1 you have: "Move 'pending' and 'requested' setting out of fc_disc_gpn_fc_req() into the calling function. No functional change." But why do you need to move the 'pending' and 'requested' settings? With an a bit more verbose changelog Acked-by: Johannes Thumshirnfor the whole series -- Johannes Thumshirn Storage jthumsh...@suse.de+49 911 74053 689 SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg) Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
SCSI controller with CDB-16 (Was: sym53c8xx and Large disk (DCB-16))
Hello, linux-scsi! I've re replaced sym53c8xx SCSI controller with Adaptec ASC-29320ALP (chip AIC-7901). - Ultra320 bus does not work physically, too many errors. - Ultra160 bus works relable, no errors. Unfortunately Adaptec does not work with CDB-16 too :( scsi11 : Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev 3.0 aic7901: Ultra320 Wide Channel A, SCSI Id=7, PCI-X 101-133MHz, 512 SCBs scsi 11:0:0:0: Direct-Access IFT A24U-G2421-1 347R PQ: 0 ANSI: 5 scsi target11:0:0: asynchronous scsi11:A:0:0: Tagged Queuing enabled. Depth 4 scsi target11:0:0: Beginning Domain Validation scsi target11:0:0: wide asynchronous scsi target11:0:0: FAST-80 WIDE SCSI 160.0 MB/s DT (12.5 ns, offset 127) scsi target11:0:0: Ending Domain Validation sd 11:0:0:0: [sde] Very big device. Trying to use READ CAPACITY(16). sd 11:0:0:0: [sde] READ CAPACITY(16) failed sd 11:0:0:0: [sde] Result: hostbyte=DID_ABORT driverbyte=DRIVER_OK sd 11:0:0:0: [sde] Sense not available. sd 11:0:0:0: [sde] Using 0x as device size sd 11:0:0:0: [sde] 4294967296 512-byte logical blocks: (2.19 TB/2.00 TiB) sd 11:0:0:0: [sde] Write Protect is off sd 11:0:0:0: [sde] Mode Sense: 9b 00 00 08 sd 11:0:0:0: [sde] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA sd 11:0:0:0: [sde] Very big device. Trying to use READ CAPACITY(16). sd 11:0:0:0: [sde] READ CAPACITY(16) failed sd 11:0:0:0: [sde] Result: hostbyte=DID_ABORT driverbyte=DRIVER_OK sd 11:0:0:0: [sde] Sense not available. sd 11:0:0:0: [sde] Using 0x as device size sd 11:0:0:0: Attached scsi generic sg5 type 0 sde: unknown partition table sd 11:0:0:0: [sde] Very big device. Trying to use READ CAPACITY(16). sd 11:0:0:0: [sde] READ CAPACITY(16) failed sd 11:0:0:0: [sde] Result: hostbyte=DID_ABORT driverbyte=DRIVER_OK sd 11:0:0:0: [sde] Sense not available. sd 11:0:0:0: [sde] Using 0x as device size sd 11:0:0:0: [sde] Attached SCSI disk CAN ANYONE PLEASE recommend a working Ultra320 SCSI controller with CDB-16 support ? 2017-04-27 18:33 GMT+03:00 Alexander Voropay: > Hi! > > I have a nasty bug with ‘sym53c8xx_2’ SCSI driver. I’m trying to > attach a large (>2Tb) storage to this controller but it does not work. > Seems nobody tested such combination before... > > > My SCSI controller is noname OEM for Intel, PCI-X card with SYN53C1010 chip. > Storage: Infortrend A24U-G2421-1 (upto 24 SATA disks to Ulra-320 SCSI > channel). > I have 11x1Tb RAID5 as one large disk with 10Tb in size. > My Linux is RHEL 6, kernel "kernel-2.6.32-696.1.1.el6.x86_64". > > Physical SCSI link is OK, full Ultra-160, no physical/parity errors > e.t.c. BUT IT DOES NOT WORK due to a software error. > > As it is known, Linux’s ‘sd’ uses CDB-16 command set for large SCSI > disks. On the other hand ‘sym53c8xx_2’ driver “Utilizes SCRIPTS > Load/Store command” and “Handles Phase Mismatch from SCRIPTS”. Seems > there is a software error between driver and “sd”. As a result ALL > disk operations are damn slow and gives a phase error in the “dmesg”: > sd 4:0:0:0: phase change 2-7 16@37a9af60 resid=10. > sd 4:0:0:0: phase change 2-7 16@37a9af60 resid=10. > sd 4:0:0:0: phase change 2-7 16@37a9af60 resid=10. > e.t.c. > > Another problem: “sd” incorrectly determines a disk size. Note a > “phase change” errors after and before “capacity change”. As a result > “sd” switches to CDB-10 and maximum disk size limited by 2Tb > > sym53c8xx : 05:01.0: PCI INT A disabled > sym53c8xx : 05:01.0: PCI INT A -> GSI 24 (level, low) -> IRQ 24 > sym0: <1010-66> rev 0x1 at pci : 05:01.0 irq 24 > sym0: Symbios NVRAM, ID 7, Fast-80, LVD, parity checking > sym0: open drain IRQ line driver, using on-chip SRAM > sym0: using LOAD/STORE-based firmware. > sym0: handling phase mismatch from SCRIPTS. > sym0: SCSI BUS has been reset. > scsi4 : sym-2.2.3 > scsi 4:0:0:0: Direct-Access IFT A24U-G2421-1 347R PQ: 0 ANSI: 5 > scsi target4:0:0: tagged command queuing enabled, command queue depth 16. > scsi target4:0:0: Beginning Domain Validation > scsi target4:0:0: FAST-80 WIDE SCSI 160.0 MB/s DT (12.5 ns, offset 62) > scsi target4:0:0: Ending Domain Validation > sd 4:0:0:0: phase change 2-7 16@37a9af60 resid=10. > sd 4:0:0:0: [sde] 4294967296 512-byte logical blocks: (2.19 TB/2.00 TiB) > sd 4:0:0:0: [sde] Write Protect is off > sd 4:0:0:0: [sde] Mode Sense: 9b 00 00 08 > sd 4:0:0:0: [sde] Write cache: enabled, read cache: enabled, doesn't > support DPO or FUA > sd 4:0:0:0: phase change 2-7 16@37a9af60 resid=10. > sd 4:0:0:0: Attached scsi generic sg5 type 0 > sd 4:0:0:0: [sde] 19529912320 512-byte logical blocks: (9.99 TB/9.09 TiB) > sde: detected capacity change from 219902322 to 315107840 > sde: unknown partition table > sd 4:0:0:0: phase change 2-7 16@37a9af60 resid=10. > sd 4:0:0:0: [sde] 4294967296 512-byte logical blocks: (2.19 TB/2.00 TiB) > sd 4:0:0:0: [sde] Attached SCSI disk > > As a result ‘parted’ does not work too, it hangs on
[PATCH 09/15] lpfc: Fix return value of board_mode store routine in case of online failure
On hbacmd reset failure, observing wrong string "nline" in kernel log. On failure, non negative value (1) is returned from sysfs store routine. It is interpreted as count by kernel and store routine is called again with the remaining characters as input. Fix: Return negative error code (-EIO) in case of failure. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_attr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index eb33473cbc62..8eee39de15f7 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1351,6 +1351,8 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, goto board_mode_out; } wait_for_completion(_compl); + if (status) + status = -EIO; } else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0) -- 2.11.0
[PATCH 00/15] lpfc updates for 11.4.0.0
This patch set provides a number of bug fixes, code cleanups, and error handling in lpfc. The patches were cut against the Martin's 4.12/scsi-fixes tree. There are no outside dependencies. The patches should merge via Martin's tree. James Smart (15): lpfc: Add nvme initiator devloss support lpfc: Fix transition nvme-i rport handling to nport only. lpfc: Fix nvme port role handling in sysfs and debugfs handlers. lpfc: Add changes to assist in NVMET debugging lpfc: Fix Lun Priority level shown as NA lpfc: Fix nvmet node ref count handling lpfc: Fix Port going offline after multiple resets. lpfc: Fix counters so outstandng NVME IO count is accurate lpfc: Fix return value of board_mode store routine in case of online failure lpfc: Fix crash on powering off BFS VM with passthrough device lpfc: Fix System panic after loading the driver lpfc: Null pointer dereference when log_verbose is set to 0x lpfc: Fix PRLI retry handling when target rejects it. lpfc: Fix vports not logging into target lpfc: update to revision to 11.4.0.0 drivers/scsi/lpfc/lpfc.h | 20 ++-- drivers/scsi/lpfc/lpfc_attr.c| 74 -- drivers/scsi/lpfc/lpfc_ct.c | 31 +++--- drivers/scsi/lpfc/lpfc_debugfs.c | 72 -- drivers/scsi/lpfc/lpfc_els.c | 17 +++- drivers/scsi/lpfc/lpfc_hbadisc.c | 14 +-- drivers/scsi/lpfc/lpfc_init.c| 21 +++- drivers/scsi/lpfc/lpfc_nvme.c| 178 - drivers/scsi/lpfc/lpfc_nvme.h| 2 - drivers/scsi/lpfc/lpfc_nvmet.c | 208 +++ drivers/scsi/lpfc/lpfc_nvmet.h | 14 +-- drivers/scsi/lpfc/lpfc_scsi.c| 19 +++- drivers/scsi/lpfc/lpfc_sli.c | 19 +++- drivers/scsi/lpfc/lpfc_sli4.h| 4 +- drivers/scsi/lpfc/lpfc_version.h | 2 +- 15 files changed, 398 insertions(+), 297 deletions(-) -- 2.11.0
[PATCH 07/15] lpfc: Fix Port going offline after multiple resets.
Observing lpfc port down after issuing hbacmd reset command Failure in posting SGL buffers. If there is only one SGL buffer and rrq is valid for its XRI, we are rightly returning NULL but not adding the buffer back to the SGL list. So, number of buffers become less than total count and repost fails during reset. Add SGL buffer back to list before returning NULL. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_sli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index d6b184839bc2..e81fa7d4deb5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -968,6 +968,7 @@ __lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) list_remove_head(lpfc_els_sgl_list, sglq, struct lpfc_sglq, list); if (sglq == start_sglq) { + list_add_tail(>list, lpfc_els_sgl_list); sglq = NULL; break; } else -- 2.11.0
[PATCH 15/15] lpfc: update to revision to 11.4.0.0
Set lpfc driver revision to 11.4.0.0 Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index c2653244221c..067c9e8a4b2d 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 "11.2.0.14" +#define LPFC_DRIVER_VERSION "11.4.0.0" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- 2.11.0
[PATCH 10/15] lpfc: Fix crash on powering off BFS VM with passthrough device
Null pointer dereference when BFS VM is powered off The driver incorrectly uses sli3_ring on SLI-4 adapters Use the correct ring structure based on sli_rev Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_sli.c | 12 ++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e81fa7d4deb5..c4ceef69bd6b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -10951,6 +10951,7 @@ 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; int i; @@ -11004,8 +11005,15 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, /* Setup callback routine and issue the command. */ abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - ret_val = lpfc_sli_issue_iocb(phba, pring->ringno, - abtsiocb, 0); + 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); errcnt++; -- 2.11.0
[PATCH 04/15] lpfc: Add changes to assist in NVMET debugging
Inconsistent error messages and context state checks Context state sanity checks were not accurate or inconsistent in the code paths. Separated LS context states from FCP. Added and modified context state sanity checks. Use context state to determine if a sol or unsol ABORT is needed. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_nvmet.c | 208 - drivers/scsi/lpfc/lpfc_nvmet.h | 14 +-- 2 files changed, 151 insertions(+), 71 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index f94294b77b7b..e062c317e2f6 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -112,6 +112,15 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, status = bf_get(lpfc_wcqe_c_status, wcqe); result = wcqe->parameter; + ctxp = cmdwqe->context2; + + if (ctxp->state != LPFC_NVMET_STE_LS_RSP || ctxp->entry_cnt != 2) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6410 NVMET LS cmpl state mismatch IO x%x: " + "%d %d\n", + ctxp->oxid, ctxp->state, ctxp->entry_cnt); + } + if (!phba->targetport) goto out; @@ -123,15 +132,14 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, atomic_inc(>xmt_ls_rsp_cmpl); out: - ctxp = cmdwqe->context2; rsp = >ctx.ls_req; lpfc_nvmeio_data(phba, "NVMET LS CMPL: xri x%x stat x%x result x%x\n", ctxp->oxid, status, result); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, - "6038 %s: Entrypoint: ctx %p status %x/%x\n", __func__, - ctxp, status, result); + "6038 NVMET LS rsp cmpl: %d %d oxid x%x\n", + status, result, ctxp->oxid); lpfc_nlp_put(cmdwqe->context1); cmdwqe->context2 = NULL; @@ -173,6 +181,12 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) ctxp->txrdy = NULL; ctxp->txrdy_phys = 0; } + + if (ctxp->state == LPFC_NVMET_STE_FREE) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6411 NVMET free, already free IO x%x: %d %d\n", + ctxp->oxid, ctxp->state, ctxp->entry_cnt); + } ctxp->state = LPFC_NVMET_STE_FREE; spin_lock_irqsave(>sli4_hba.nvmet_io_wait_lock, iflag); @@ -580,8 +594,17 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, int rc; lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, - "6023 %s: Entrypoint ctx %p %p\n", __func__, - ctxp, tgtport); + "6023 NVMET LS rsp oxid x%x\n", ctxp->oxid); + + if ((ctxp->state != LPFC_NVMET_STE_LS_RCV) || + (ctxp->entry_cnt != 1)) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6412 NVMET LS rsp state mismatch " + "oxid x%x: %d %d\n", + ctxp->oxid, ctxp->state, ctxp->entry_cnt); + } + ctxp->state = LPFC_NVMET_STE_LS_RSP; + ctxp->entry_cnt++; nvmewqeq = lpfc_nvmet_prep_ls_wqe(phba, ctxp, rsp->rspdma, rsp->rsplen); @@ -751,15 +774,14 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, unsigned long flags; lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6103 Abort op: oxri x%x flg x%x cnt %d\n", - ctxp->oxid, ctxp->flag, ctxp->entry_cnt); + "6103 NVMET Abort op: oxri x%x flg x%x ste %d\n", + ctxp->oxid, ctxp->flag, ctxp->state); - lpfc_nvmeio_data(phba, "NVMET FCP ABRT: " -"xri x%x flg x%x cnt x%x\n", -ctxp->oxid, ctxp->flag, ctxp->entry_cnt); + lpfc_nvmeio_data(phba, "NVMET FCP ABRT: xri x%x flg x%x ste x%x\n", +ctxp->oxid, ctxp->flag, ctxp->state); atomic_inc(_nvmep->xmt_fcp_abort); - ctxp->entry_cnt++; + spin_lock_irqsave(>ctxlock, flags); /* Since iaab/iaar are NOT set, we need to check @@ -770,12 +792,17 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, return; } ctxp->flag |= LPFC_NVMET_ABORT_OP; - if (ctxp->flag & LPFC_NVMET_IO_INP) - lpfc_nvmet_sol_fcp_issue_abort(phba, ctxp, ctxp->sid, - ctxp->oxid); - else + + /* An state of LPFC_NVMET_STE_RCV means we have just received +* the NVME command and have not started
[PATCH 13/15] lpfc: Fix PRLI retry handling when target rejects it.
The nvmet driver was rejecting the initiator's PRLI because its reg_rpi for the PLOGI was still outstanding. The initiator would resend the PRLI without delay and get the same answer. The PRLI retries would exhaust causing the nvme initiator to set the nvmet ndlp to UNMAPPED. The driver's lpfc_els_retry handler did not have a policy for an LS_RJT with explanation CMD_IN_PROGRESS for PRLI or NVME_PRLI. This caused the delay to remain at 0 but retry set 1. Fix: When the ELS response is LS_RJT, TPC and the command was PRLI or NVME_PRLI, just set the delay to 1000 mS to get a 1 second delay on the PRLI retry. This was enough to allow the REG_RPI to complete at the target. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_els.c | 17 ++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 8e532b39ae93..a140318d6159 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3332,6 +3332,19 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ switch (stat.un.b.lsRjtRsnCode) { case LSRJT_UNABLE_TPC: + /* The driver has a VALID PLOGI but the rport has +* rejected the PRLI - can't do it now. Delay +* for 1 second and try again - don't care about +* the explanation. +*/ + if (cmd == ELS_CMD_PRLI || cmd == ELS_CMD_NVMEPRLI) { + delay = 1000; + maxretry = lpfc_max_els_tries + 1; + retry = 1; + break; + } + + /* Legacy bug fix code for targets with PLOGI delays. */ if (stat.un.b.lsRjtRsnCodeExp == LSEXP_CMD_IN_PROGRESS) { if (cmd == ELS_CMD_PLOGI) { @@ -3350,9 +3363,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, retry = 1; break; } - if ((cmd == ELS_CMD_PLOGI) || - (cmd == ELS_CMD_PRLI) || - (cmd == ELS_CMD_NVMEPRLI)) { + if (cmd == ELS_CMD_PLOGI) { delay = 1000; maxretry = lpfc_max_els_tries + 1; retry = 1; -- 2.11.0
[PATCH 14/15] lpfc: Fix vports not logging into target
vports cannot login to target. For vports, lpfc_nodelist is allocated for targets only on completion of GFF_ID command. Driver checks if lpfc_nodelist exists for target before sending GFF_ID. So, GFF_ID and PLOGI are not sent. As mentioned by the comment in lpfc_prep_node_fc4type() routine, do not send GFF_ID only if this NPortID is previously identified as FCP target. Send GFF_ID if it is a newly identified remote port from GID_FT response. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_ct.c | 31 ++- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index f2cd19c6c2df..2853a6d352f8 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -503,26 +503,23 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) Did, vport->fc_flag, vport->fc_rscn_id_cnt); /* -* This NPortID was previously a FCP target, +* This NPortID was previously a FCP/NVMe target, * Don't even bother to send GFF_ID. */ ndlp = lpfc_findnode_did(vport, Did); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) - ndlp->nlp_fc4_type = fc4_type; - - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - ndlp->nlp_fc4_type = fc4_type; - - if (ndlp->nlp_type & NLP_FCP_TARGET) - lpfc_setup_disc_node(vport, Did); - - else if (lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID, - 0, Did) == 0) - vport->num_disc_nodes++; - - else - lpfc_setup_disc_node(vport, Did); - } + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + (ndlp->nlp_type & + (NLP_FCP_TARGET | NLP_NVME_TARGET))) { + if (fc4_type == FC_TYPE_FCP) + ndlp->nlp_fc4_type |= NLP_FC4_FCP; + if (fc4_type == FC_TYPE_NVME) + ndlp->nlp_fc4_type |= NLP_FC4_NVME; + lpfc_setup_disc_node(vport, Did); + } else if (lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID, + 0, Did) == 0) + vport->num_disc_nodes++; + else + lpfc_setup_disc_node(vport, Did); } else { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "Skip2 GID_FTrsp: did:x%x flg:x%x cnt:%d", -- 2.11.0
[PATCH 06/15] lpfc: Fix nvmet node ref count handling
When unloading the driver, the NVMET driver would wait the full 30 seconds for its UNMAPPED initiator node to get removed before continuing with the unload process. NVMEI worked correctly. For each rport put into UNMAPPED or MAPPED state by NVMET, the driver puts a reference on the NDLP. The difference is that NVMEI has a unregister call for its rports and the extra reference is removed in the unregister process. For NVMET, the driver has to remove the reference explicitly when dropping out of UNMAPPED or MAPPED because there is no unregister call. Add a call to lpfc_nlp_put on the ndlp when NVMET and the old state was UNMAPPED or MAPPED. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_hbadisc.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 055fedd761ea..db2d0e692ddf 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4167,14 +4167,14 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_unregister_remote_port(ndlp); } - /* Notify the NVME transport of this rport's loss on the -* Initiator. For NVME Target, should upcall transport -* in the else clause when API available. -*/ if (ndlp->nlp_fc4_type & NLP_FC4_NVME) { vport->phba->nport_event_cnt++; if (vport->phba->nvmet_support == 0) + /* Start devloss */ lpfc_nvme_unregister_port(vport, ndlp); + else + /* NVMET has no upcall. */ + lpfc_nlp_put(ndlp); } } -- 2.11.0
[PATCH 01/15] lpfc: Add nvme initiator devloss support
Add nvme initiator devloss support The existing implementation was based on no devloss behavior in the transport (e.g. immediate teardown) so code didn't properly handle delayed nvme rport device unregister calls. In addition, the driver was not correctly cycling the rport port role for each register-unregister-reregister process. This patch does the following: Rework the code to properly handle rport device unregister calls and potential re-allocation of the remoteport structure if the port comes back in under dev_loss_tmo. Correct code that was incorrectly cycling the rport port role for each register-unregister-reregister process. Prep the code to enable calling the nvme_fc transport api to dynamically update dev_loss_tmo when the scsi sysfs interface changes it. Memset the rpinfo structure in the registration call to enforce "accept nvme transport defaults" in the registration call. Driver parameters do influence the dev_loss_tmo transport setting dynamically. Simplifies the register function: the driver was incorrectly searching its local rport list to determine resume or new semantics, which is not valid as the transport already handles this. The rport was resumed if the rport handed back matches the ndlp->nrport pointer. Otherwise, devloss fired and the ndlp's nrport is NULL. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_attr.c | 7 ++- drivers/scsi/lpfc/lpfc_nvme.c | 141 -- 2 files changed, 57 insertions(+), 91 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index bb2d9e238225..37f258fcf6d4 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3198,9 +3198,12 @@ 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, >fc_nodes, nlp_listp) - if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport) + list_for_each_entry(ndlp, >fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; + if (ndlp->rport) ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; + } spin_unlock_irq(shost->host_lock); } diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 8008c8205fb6..70675fd7d884 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -186,13 +186,13 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) /* 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, this is devloss = 0 -* semantics. +* calling state machine to remove the node. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6146 remoteport delete complete %p\n", remoteport); list_del(>list); + ndlp->nrport = NULL; lpfc_nlp_put(ndlp); rport_err: @@ -1466,7 +1466,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* The remote node has to be ready to send an abort. */ if ((ndlp->nlp_state != NLP_STE_MAPPED_NODE) && - !(ndlp->nlp_type & NLP_NVME_TARGET)) { + (ndlp->nlp_type & NLP_NVME_TARGET)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, "6048 rport %p, DID x%06x not ready for " "IO. State x%x, Type x%x\n", @@ -2340,69 +2340,44 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) localport = vport->localport; lport = (struct lpfc_nvme_lport *)localport->private; - if (ndlp->nlp_type & (NLP_NVME_TARGET | NLP_NVME_INITIATOR)) { - - /* The driver isn't expecting the rport wwn to change -* but it might get a different DID on a different -* fabric. + /* NVME rports are not preserved across devloss. +* Just register this instance. Note, rpinfo->dev_loss_tmo +* is left 0 to indicate accept transport defaults. The +* driver communicates port role capabilities consistent +* with the PRLI response data. +*/ + memset(, 0, sizeof(struct nvme_fc_port_info)); + rpinfo.port_id = ndlp->nlp_DID; + if (ndlp->nlp_type & NLP_NVME_TARGET) + rpinfo.port_role |= FC_PORT_ROLE_NVME_TARGET; + if (ndlp->nlp_type & NLP_NVME_INITIATOR) + rpinfo.port_role |= FC_PORT_ROLE_NVME_INITIATOR; + + if (ndlp->nlp_type & NLP_NVME_DISCOVERY) + rpinfo.port_role |= FC_PORT_ROLE_NVME_DISCOVERY; + + rpinfo.port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn); +
[PATCH 02/15] lpfc: Fix transition nvme-i rport handling to nport only.
As the devloss API was implemented in the nvmei driver, an evaluation of the nvme transport and the lpfc driver showed dual management of the rports. This creates a bug possibility when the thread count and SAN size increases. The nvmei driver code was based on a very early transport and was not revisited until the devloss API was introduced. Remove the listhead in the driver's rport data structure and the listhead in the driver's lport data structure. Remove all rport_list traversal. Convert the driver to use the nrport (nvme rport) pointer that is now NULL or nonNULL depending on a devloss action. Convert debugfs and nvme_info in sysfs to use the fc_nodes list in the vport. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_attr.c| 11 ++- drivers/scsi/lpfc/lpfc_debugfs.c | 10 +- drivers/scsi/lpfc/lpfc_nvme.c| 18 -- drivers/scsi/lpfc/lpfc_nvme.h| 2 -- 4 files changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 37f258fcf6d4..6d9b83cd82a2 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -148,8 +148,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = vport->phba; struct lpfc_nvmet_tgtport *tgtp; struct nvme_fc_local_port *localport; - struct lpfc_nvme_lport *lport; - struct lpfc_nvme_rport *rport; + struct lpfc_nodelist *ndlp; struct nvme_fc_remote_port *nrport; char *statep; int len = 0; @@ -265,7 +264,6 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, len = snprintf(buf, PAGE_SIZE, "NVME Initiator Enabled\n"); spin_lock_irq(shost->host_lock); - lport = (struct lpfc_nvme_lport *)localport->private; /* Port state is only one of two values for now. */ if (localport->port_id) @@ -281,9 +279,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, wwn_to_u64(vport->fc_nodename.u.wwn), localport->port_id, statep); - list_for_each_entry(rport, >rport_list, list) { + list_for_each_entry(ndlp, >fc_nodes, nlp_listp) { + if (!ndlp->nrport) + continue; + /* local short-hand pointer. */ - nrport = rport->remoteport; + nrport = ndlp->nrport->remoteport; /* Port state is only one of two values for now. */ switch (nrport->port_state) { diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 4bcb92c844ca..d71bda24b08e 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -550,8 +550,6 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) struct lpfc_nodelist *ndlp; unsigned char *statep; struct nvme_fc_local_port *localport; - struct lpfc_nvme_lport *lport; - struct lpfc_nvme_rport *rport; struct lpfc_nvmet_tgtport *tgtp; struct nvme_fc_remote_port *nrport; @@ -660,7 +658,6 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) goto out_exit; spin_lock_irq(shost->host_lock); - lport = (struct lpfc_nvme_lport *)localport->private; /* Port state is only one of two values for now. */ if (localport->port_id) @@ -673,9 +670,12 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) localport->port_id, statep); len += snprintf(buf + len, size - len, "\tRport List:\n"); - list_for_each_entry(rport, >rport_list, list) { + list_for_each_entry(ndlp, >fc_nodes, nlp_listp) { /* local short-hand pointer. */ - nrport = rport->remoteport; + if (!ndlp->nrport) + continue; + + nrport = ndlp->nrport->remoteport; /* Port state is only one of two values for now. */ switch (nrport->port_state) { diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 70675fd7d884..ede42411e57b 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -191,7 +191,6 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6146 remoteport delete complete %p\n", remoteport); - list_del(>list); ndlp->nrport = NULL; lpfc_nlp_put(ndlp); @@ -2208,7 +2207,6 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) lport = (struct lpfc_nvme_lport *)localport->private; vport->localport = localport; lport->vport = vport; -
[PATCH 12/15] lpfc: Null pointer dereference when log_verbose is set to 0xffffffff
Kernel panic when log_verbose is set to 0x phba->pport is dereferenced before it is initialized Fix: Do not dereference phba->pport if it is NULL Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_sli.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index c4ceef69bd6b..fb4c708ae747 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -7513,7 +7513,8 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, "(%d):0308 Mbox cmd issue - BUSY Data: " "x%x x%x x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0xff, - mbx->mbxCommand, phba->pport->port_state, + mbx->mbxCommand, + phba->pport ? phba->pport->port_state : 0xff, psli->sli_flag, flag); psli->slistat.mbox_busy++; @@ -7565,7 +7566,8 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, "(%d):0309 Mailbox cmd x%x issue Data: x%x x%x " "x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, - mbx->mbxCommand, phba->pport->port_state, + mbx->mbxCommand, + phba->pport ? phba->pport->port_state : 0xff, psli->sli_flag, flag); if (mbx->mbxCommand != MBX_HEARTBEAT) { -- 2.11.0
[PATCH 08/15] lpfc: Fix counters so outstandng NVME IO count is accurate
NVME FC counters don't reflect actual results Since counters are not atomic, or protected by a lock, the values often get screwed up. Make them atomic, like NVMET. Fix up sysfs and debugfs display accordingly Added Outstanding IOs to stats display Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc.h | 20 ++-- drivers/scsi/lpfc/lpfc_attr.c| 32 +--- drivers/scsi/lpfc/lpfc_debugfs.c | 30 +- drivers/scsi/lpfc/lpfc_init.c| 10 ++ drivers/scsi/lpfc/lpfc_nvme.c| 19 +-- drivers/scsi/lpfc/lpfc_scsi.c| 19 ++- 6 files changed, 89 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index f2c0ba6ced78..a9d73728a68c 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -913,16 +913,16 @@ struct lpfc_hba { /* * stat counters */ - uint64_t fc4ScsiInputRequests; - uint64_t fc4ScsiOutputRequests; - uint64_t fc4ScsiControlRequests; - uint64_t fc4ScsiIoCmpls; - uint64_t fc4NvmeInputRequests; - uint64_t fc4NvmeOutputRequests; - uint64_t fc4NvmeControlRequests; - uint64_t fc4NvmeIoCmpls; - uint64_t fc4NvmeLsRequests; - uint64_t fc4NvmeLsCmpls; + atomic_t fc4ScsiInputRequests; + atomic_t fc4ScsiOutputRequests; + atomic_t fc4ScsiControlRequests; + atomic_t fc4ScsiIoCmpls; + atomic_t fc4NvmeInputRequests; + atomic_t fc4NvmeOutputRequests; + atomic_t fc4NvmeControlRequests; + atomic_t fc4NvmeIoCmpls; + atomic_t fc4NvmeLsRequests; + atomic_t fc4NvmeLsCmpls; uint64_t bg_guard_err_cnt; uint64_t bg_apptag_err_cnt; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 200a614bb540..eb33473cbc62 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -150,6 +150,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, struct nvme_fc_local_port *localport; struct lpfc_nodelist *ndlp; struct nvme_fc_remote_port *nrport; + uint64_t data1, data2, data3, tot; char *statep; int len = 0; @@ -244,11 +245,18 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, atomic_read(>xmt_abort_rsp), atomic_read(>xmt_abort_rsp_error)); + spin_lock(>sli4_hba.nvmet_io_lock); + tot = phba->sli4_hba.nvmet_xri_cnt - + phba->sli4_hba.nvmet_ctx_cnt; + spin_unlock(>sli4_hba.nvmet_io_lock); + len += snprintf(buf + len, PAGE_SIZE - len, - "IO_CTX: %08x outstanding %08x total %x", + "IO_CTX: %08x WAIT: cur %08x tot %08x\n" + "CTX Outstanding %08llx\n", phba->sli4_hba.nvmet_ctx_cnt, phba->sli4_hba.nvmet_io_wait_cnt, - phba->sli4_hba.nvmet_io_wait_total); + phba->sli4_hba.nvmet_io_wait_total, + tot); len += snprintf(buf+len, PAGE_SIZE-len, "\n"); return len; @@ -337,19 +345,21 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, len += snprintf(buf + len, PAGE_SIZE - len, "\nNVME Statistics\n"); len += snprintf(buf+len, PAGE_SIZE-len, - "LS: Xmt %016llx Cmpl %016llx\n", - phba->fc4NvmeLsRequests, - phba->fc4NvmeLsCmpls); - + "LS: Xmt %016x Cmpl %016x\n", + atomic_read(>fc4NvmeLsRequests), + atomic_read(>fc4NvmeLsCmpls)); + + tot = atomic_read(>fc4NvmeIoCmpls); + data1 = atomic_read(>fc4NvmeInputRequests); + data2 = atomic_read(>fc4NvmeOutputRequests); + data3 = atomic_read(>fc4NvmeControlRequests); len += snprintf(buf+len, PAGE_SIZE-len, "FCP: Rd %016llx Wr %016llx IO %016llx\n", - phba->fc4NvmeInputRequests, - phba->fc4NvmeOutputRequests, - phba->fc4NvmeControlRequests); + data1, data2, data3); len += snprintf(buf+len, PAGE_SIZE-len, - "Cmpl %016llx\n", phba->fc4NvmeIoCmpls); - + "Cmpl %016llx Outstanding %016llx\n", + tot, (data1 + data2 + data3) - tot); return len; } diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index dd8598bc50f3..6089690fb345 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++
[PATCH 11/15] lpfc: Fix System panic after loading the driver
System panic with general protection fault during driver load The driver uses a static array sli4_hba.handler_name to store the irq handler names. If the io_channel_irqs exceeds the pre-allocated size (32+1), then the driver will overwrite other fields of sli4_hba. Fix: Dynamically allocate handler_name. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_init.c | 11 ++- drivers/scsi/lpfc/lpfc_sli4.h | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 3064f0768033..a825806036c3 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -9665,6 +9665,7 @@ static int lpfc_sli4_enable_msix(struct lpfc_hba *phba) { int vectors, rc, index; + char *name; /* Set up MSI-X multi-message vectors */ vectors = phba->io_channel_irqs; @@ -9683,9 +9684,9 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) /* Assign MSI-X vectors to interrupt handlers */ for (index = 0; index < vectors; index++) { - memset(>sli4_hba.handler_name[index], 0, 16); - snprintf((char *)>sli4_hba.handler_name[index], -LPFC_SLI4_HANDLER_NAME_SZ, + name = phba->sli4_hba.hba_eq_hdl[index].handler_name; + memset(name, 0, LPFC_SLI4_HANDLER_NAME_SZ); + snprintf(name, LPFC_SLI4_HANDLER_NAME_SZ, LPFC_DRIVER_HANDLER_NAME"%d", index); phba->sli4_hba.hba_eq_hdl[index].idx = index; @@ -9694,12 +9695,12 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) if (phba->cfg_fof && (index == (vectors - 1))) rc = request_irq(pci_irq_vector(phba->pcidev, index), _sli4_fof_intr_handler, 0, -(char *)>sli4_hba.handler_name[index], +name, >sli4_hba.hba_eq_hdl[index]); else rc = request_irq(pci_irq_vector(phba->pcidev, index), _sli4_hba_intr_handler, 0, -(char *)>sli4_hba.handler_name[index], +name, >sli4_hba.hba_eq_hdl[index]); if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index cf863db27700..28b75e08e044 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -407,8 +407,10 @@ struct lpfc_max_cfg_param { struct lpfc_hba; /* SLI4 HBA multi-fcp queue handler struct */ +#define LPFC_SLI4_HANDLER_NAME_SZ 16 struct lpfc_hba_eq_hdl { uint32_t idx; + char handler_name[LPFC_SLI4_HANDLER_NAME_SZ]; struct lpfc_hba *phba; atomic_t hba_eq_in_use; struct cpumask *cpumask; @@ -480,7 +482,6 @@ struct lpfc_sli4_lnk_info { #define LPFC_SLI4_HANDLER_CNT (LPFC_HBA_IO_CHAN_MAX+ \ LPFC_FOF_IO_CHAN_NUM) -#define LPFC_SLI4_HANDLER_NAME_SZ 16 /* Used for IRQ vector to CPU mapping */ struct lpfc_vector_map_info { @@ -548,7 +549,6 @@ struct lpfc_sli4_hba { uint32_t ue_to_rp; struct lpfc_register sli_intf; struct lpfc_pc_sli4_params pc_sli4_params; - uint8_t handler_name[LPFC_SLI4_HANDLER_CNT][LPFC_SLI4_HANDLER_NAME_SZ]; struct lpfc_hba_eq_hdl *hba_eq_hdl; /* HBA per-WQ handle */ /* Pointers to the constructed SLI4 queues */ -- 2.11.0
[PATCH 05/15] lpfc: Fix Lun Priority level shown as NA
Lun Priority level shown as NA Remote port is not getting registered for nameserver and fdmi. Due to which dfc SendCTPassThru cmd is failing. Made changes to register the remote port for both. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_hbadisc.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 3ffcd9215ca8..055fedd761ea 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4182,8 +4182,10 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (new_state == NLP_STE_MAPPED_NODE || new_state == NLP_STE_UNMAPPED_NODE) { - if ((ndlp->nlp_fc4_type & NLP_FC4_FCP) || - (ndlp->nlp_DID == Fabric_DID)) { + if (ndlp->nlp_fc4_type & NLP_FC4_FCP || + ndlp->nlp_DID == Fabric_DID || + ndlp->nlp_DID == NameServer_DID || + ndlp->nlp_DID == FDMI_DID) { vport->phba->nport_event_cnt++; /* * Tell the fc transport about the port, if we haven't -- 2.11.0
[PATCH 03/15] lpfc: Fix nvme port role handling in sysfs and debugfs handlers.
While debugging Devloss and recovery, debugfs and sysfs were found to not show the NVME port roles consistently. The port role FC_PORT_ROLE_NVME_DISCOVERY was added with the devloss bringup and the other issues were just oversight. Add NVME Target and DISCSRVC to debugfs nodeinfo and sysfs nvme info handlers. The full port role was added to the NVME data only not the generic nodelist. Signed-off-by: Dick KennedySigned-off-by: James Smart --- drivers/scsi/lpfc/lpfc_attr.c| 22 ++ drivers/scsi/lpfc/lpfc_debugfs.c | 32 ++-- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 6d9b83cd82a2..200a614bb540 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -312,25 +312,23 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, len += snprintf(buf + len, PAGE_SIZE - len, "DID x%06x ", nrport->port_id); - switch (nrport->port_role) { - case FC_PORT_ROLE_NVME_INITIATOR: + /* An NVME rport can have multiple roles. */ + if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) len += snprintf(buf + len, PAGE_SIZE - len, "INITIATOR "); - break; - case FC_PORT_ROLE_NVME_TARGET: + if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) len += snprintf(buf + len, PAGE_SIZE - len, "TARGET "); - break; - case FC_PORT_ROLE_NVME_DISCOVERY: + if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) len += snprintf(buf + len, PAGE_SIZE - len, -"DISCOVERY "); - break; - default: +"DISCSRVC "); + if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR | + FC_PORT_ROLE_NVME_TARGET | + FC_PORT_ROLE_NVME_DISCOVERY)) len += snprintf(buf + len, PAGE_SIZE - len, -"UNKNOWN_ROLE x%x", +"UNKNOWN ROLE x%x", nrport->port_role); - break; - } + len += snprintf(buf + len, PAGE_SIZE - len, "%s ", statep); /* Terminate the string. */ len += snprintf(buf + len, PAGE_SIZE - len, "\n"); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index d71bda24b08e..dd8598bc50f3 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -621,6 +621,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) ndlp->nlp_sid); if (ndlp->nlp_type & NLP_FCP_INITIATOR) len += snprintf(buf+len, size-len, "FCP_INITIATOR "); + if (ndlp->nlp_type & NLP_NVME_TARGET) + len += snprintf(buf + len, + size - len, "NVME_TGT sid:%d ", + NLP_NO_SID); + if (ndlp->nlp_type & NLP_NVME_INITIATOR) + len += snprintf(buf + len, + size - len, "NVME_INITIATOR "); len += snprintf(buf+len, size-len, "usgmap:%x ", ndlp->nlp_usg_map); len += snprintf(buf+len, size-len, "refcnt:%x", @@ -698,26 +705,23 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) nrport->port_name); len += snprintf(buf + len, size - len, "WWNN x%llx ", nrport->node_name); - switch (nrport->port_role) { - case FC_PORT_ROLE_NVME_INITIATOR: + + /* An NVME rport can have multiple roles. */ + if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) len += snprintf(buf + len, size - len, -"NVME INITIATOR "); - break; - case FC_PORT_ROLE_NVME_TARGET: +"INITIATOR "); + if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) len += snprintf(buf + len, size - len, -"NVME TARGET "); - break; - case FC_PORT_ROLE_NVME_DISCOVERY: +"TARGET "); + if (nrport->port_role &