xref: /openbmc/linux/drivers/scsi/lpfc/lpfc_mbox.c (revision 98c9ea5c)
1dea3101eS /*******************************************************************
2dea3101eS  * This file is part of the Emulex Linux Device Driver for         *
3c44ce173SJames.Smart@Emulex.Com  * Fibre Channel Host Bus Adapters.                                *
49413afffSJames Smart  * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
5c44ce173SJames.Smart@Emulex.Com  * EMULEX and SLI are trademarks of Emulex.                        *
6dea3101eS  * www.emulex.com                                                  *
7c44ce173SJames.Smart@Emulex.Com  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
8dea3101eS  *                                                                 *
9dea3101eS  * This program is free software; you can redistribute it and/or   *
10c44ce173SJames.Smart@Emulex.Com  * modify it under the terms of version 2 of the GNU General       *
11c44ce173SJames.Smart@Emulex.Com  * Public License as published by the Free Software Foundation.    *
12c44ce173SJames.Smart@Emulex.Com  * This program is distributed in the hope that it will be useful. *
13c44ce173SJames.Smart@Emulex.Com  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
14c44ce173SJames.Smart@Emulex.Com  * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
15c44ce173SJames.Smart@Emulex.Com  * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
16c44ce173SJames.Smart@Emulex.Com  * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
17c44ce173SJames.Smart@Emulex.Com  * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
18c44ce173SJames.Smart@Emulex.Com  * more details, a copy of which can be found in the file COPYING  *
19c44ce173SJames.Smart@Emulex.Com  * included with this package.                                     *
20dea3101eS  *******************************************************************/
21dea3101eS 
22dea3101eS #include <linux/blkdev.h>
23dea3101eS #include <linux/pci.h>
24dea3101eS #include <linux/interrupt.h>
25dea3101eS 
26f888ba3cSJames.Smart@Emulex.Com #include <scsi/scsi_device.h>
27f888ba3cSJames.Smart@Emulex.Com #include <scsi/scsi_transport_fc.h>
28f888ba3cSJames.Smart@Emulex.Com 
2991886523SJames.Smart@Emulex.Com #include <scsi/scsi.h>
3091886523SJames.Smart@Emulex.Com 
31dea3101eS #include "lpfc_hw.h"
32dea3101eS #include "lpfc_sli.h"
33dea3101eS #include "lpfc_disc.h"
34dea3101eS #include "lpfc_scsi.h"
35dea3101eS #include "lpfc.h"
36dea3101eS #include "lpfc_logmsg.h"
37dea3101eS #include "lpfc_crtn.h"
38dea3101eS #include "lpfc_compat.h"
39dea3101eS 
40dea3101eS /**********************************************/
41dea3101eS 
42dea3101eS /*                mailbox command             */
43dea3101eS /**********************************************/
44dea3101eS void
45dea3101eS lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset)
46dea3101eS {
47dea3101eS 	MAILBOX_t *mb;
48dea3101eS 	void *ctx;
49dea3101eS 
50dea3101eS 	mb = &pmb->mb;
51dea3101eS 	ctx = pmb->context2;
52dea3101eS 
53dea3101eS 	/* Setup to dump VPD region */
54dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
55dea3101eS 	mb->mbxCommand = MBX_DUMP_MEMORY;
56dea3101eS 	mb->un.varDmp.cv = 1;
57dea3101eS 	mb->un.varDmp.type = DMP_NV_PARAMS;
58dea3101eS 	mb->un.varDmp.entry_index = offset;
59dea3101eS 	mb->un.varDmp.region_id = DMP_REGION_VPD;
60dea3101eS 	mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t));
61dea3101eS 	mb->un.varDmp.co = 0;
62dea3101eS 	mb->un.varDmp.resp_offset = 0;
63dea3101eS 	pmb->context2 = ctx;
64dea3101eS 	mb->mbxOwner = OWN_HOST;
65dea3101eS 	return;
66dea3101eS }
67dea3101eS 
68dea3101eS /**********************************************/
69dea3101eS /*  lpfc_read_nv  Issue a READ NVPARAM        */
70dea3101eS /*                mailbox command             */
71dea3101eS /**********************************************/
72dea3101eS void
73dea3101eS lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
74dea3101eS {
75dea3101eS 	MAILBOX_t *mb;
76dea3101eS 
77dea3101eS 	mb = &pmb->mb;
78dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
79dea3101eS 	mb->mbxCommand = MBX_READ_NV;
80dea3101eS 	mb->mbxOwner = OWN_HOST;
81dea3101eS 	return;
82dea3101eS }
83dea3101eS 
84dea3101eS /**********************************************/
8557127f15SJames Smart /*  lpfc_config_async  Issue a                */
8657127f15SJames Smart /*  MBX_ASYNC_EVT_ENABLE mailbox command      */
8757127f15SJames Smart /**********************************************/
8857127f15SJames Smart void
8957127f15SJames Smart lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
9057127f15SJames Smart 		uint32_t ring)
9157127f15SJames Smart {
9257127f15SJames Smart 	MAILBOX_t *mb;
9357127f15SJames Smart 
9457127f15SJames Smart 	mb = &pmb->mb;
9557127f15SJames Smart 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
9657127f15SJames Smart 	mb->mbxCommand = MBX_ASYNCEVT_ENABLE;
9757127f15SJames Smart 	mb->un.varCfgAsyncEvent.ring = ring;
9857127f15SJames Smart 	mb->mbxOwner = OWN_HOST;
9957127f15SJames Smart 	return;
10057127f15SJames Smart }
10157127f15SJames Smart 
10257127f15SJames Smart /**********************************************/
103858c9f6cSJames Smart /*  lpfc_heart_beat  Issue a HEART_BEAT       */
104858c9f6cSJames Smart /*                mailbox command             */
105858c9f6cSJames Smart /**********************************************/
106858c9f6cSJames Smart void
107858c9f6cSJames Smart lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
108858c9f6cSJames Smart {
109858c9f6cSJames Smart 	MAILBOX_t *mb;
110858c9f6cSJames Smart 
111858c9f6cSJames Smart 	mb = &pmb->mb;
112858c9f6cSJames Smart 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
113858c9f6cSJames Smart 	mb->mbxCommand = MBX_HEARTBEAT;
114858c9f6cSJames Smart 	mb->mbxOwner = OWN_HOST;
115858c9f6cSJames Smart 	return;
116858c9f6cSJames Smart }
117858c9f6cSJames Smart 
118858c9f6cSJames Smart /**********************************************/
119dea3101eS /*  lpfc_read_la  Issue a READ LA             */
120dea3101eS /*                mailbox command             */
121dea3101eS /**********************************************/
122dea3101eS int
123dea3101eS lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp)
124dea3101eS {
125dea3101eS 	MAILBOX_t *mb;
126dea3101eS 	struct lpfc_sli *psli;
127dea3101eS 
128dea3101eS 	psli = &phba->sli;
129dea3101eS 	mb = &pmb->mb;
130dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
131dea3101eS 
132dea3101eS 	INIT_LIST_HEAD(&mp->list);
133dea3101eS 	mb->mbxCommand = MBX_READ_LA64;
134dea3101eS 	mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128;
135dea3101eS 	mb->un.varReadLA.un.lilpBde64.addrHigh = putPaddrHigh(mp->phys);
136dea3101eS 	mb->un.varReadLA.un.lilpBde64.addrLow = putPaddrLow(mp->phys);
137dea3101eS 
138dea3101eS 	/* Save address for later completion and set the owner to host so that
139dea3101eS 	 * the FW knows this mailbox is available for processing.
140dea3101eS 	 */
141dea3101eS 	pmb->context1 = (uint8_t *) mp;
142dea3101eS 	mb->mbxOwner = OWN_HOST;
14392d7f7b0SJames Smart 	return (0);
144dea3101eS }
145dea3101eS 
146dea3101eS /**********************************************/
147dea3101eS /*  lpfc_clear_la  Issue a CLEAR LA           */
148dea3101eS /*                 mailbox command            */
149dea3101eS /**********************************************/
150dea3101eS void
151dea3101eS lpfc_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
152dea3101eS {
153dea3101eS 	MAILBOX_t *mb;
154dea3101eS 
155dea3101eS 	mb = &pmb->mb;
156dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
157dea3101eS 
158dea3101eS 	mb->un.varClearLA.eventTag = phba->fc_eventTag;
159dea3101eS 	mb->mbxCommand = MBX_CLEAR_LA;
160dea3101eS 	mb->mbxOwner = OWN_HOST;
161dea3101eS 	return;
162dea3101eS }
163dea3101eS 
164dea3101eS /**************************************************/
165dea3101eS /*  lpfc_config_link  Issue a CONFIG LINK         */
166dea3101eS /*                    mailbox command             */
167dea3101eS /**************************************************/
168dea3101eS void
169dea3101eS lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
170dea3101eS {
1712e0fef85SJames Smart 	struct lpfc_vport  *vport = phba->pport;
172dea3101eS 	MAILBOX_t *mb = &pmb->mb;
173dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
174dea3101eS 
175dea3101eS 	/* NEW_FEATURE
176dea3101eS 	 * SLI-2, Coalescing Response Feature.
177dea3101eS 	 */
178dea3101eS 	if (phba->cfg_cr_delay) {
179dea3101eS 		mb->un.varCfgLnk.cr = 1;
180dea3101eS 		mb->un.varCfgLnk.ci = 1;
181dea3101eS 		mb->un.varCfgLnk.cr_delay = phba->cfg_cr_delay;
182dea3101eS 		mb->un.varCfgLnk.cr_count = phba->cfg_cr_count;
183dea3101eS 	}
184dea3101eS 
1852e0fef85SJames Smart 	mb->un.varCfgLnk.myId = vport->fc_myDID;
186dea3101eS 	mb->un.varCfgLnk.edtov = phba->fc_edtov;
187dea3101eS 	mb->un.varCfgLnk.arbtov = phba->fc_arbtov;
188dea3101eS 	mb->un.varCfgLnk.ratov = phba->fc_ratov;
189dea3101eS 	mb->un.varCfgLnk.rttov = phba->fc_rttov;
190dea3101eS 	mb->un.varCfgLnk.altov = phba->fc_altov;
191dea3101eS 	mb->un.varCfgLnk.crtov = phba->fc_crtov;
192dea3101eS 	mb->un.varCfgLnk.citov = phba->fc_citov;
193dea3101eS 
194dea3101eS 	if (phba->cfg_ack0)
195dea3101eS 		mb->un.varCfgLnk.ack0_enable = 1;
196dea3101eS 
197dea3101eS 	mb->mbxCommand = MBX_CONFIG_LINK;
198dea3101eS 	mb->mbxOwner = OWN_HOST;
199dea3101eS 	return;
200dea3101eS }
201dea3101eS 
202dea3101eS /**********************************************/
203dea3101eS /*  lpfc_init_link  Issue an INIT LINK        */
204dea3101eS /*                  mailbox command           */
205dea3101eS /**********************************************/
206dea3101eS void
207dea3101eS lpfc_init_link(struct lpfc_hba * phba,
208dea3101eS 	       LPFC_MBOXQ_t * pmb, uint32_t topology, uint32_t linkspeed)
209dea3101eS {
210dea3101eS 	lpfc_vpd_t *vpd;
211dea3101eS 	struct lpfc_sli *psli;
212dea3101eS 	MAILBOX_t *mb;
213dea3101eS 
214dea3101eS 	mb = &pmb->mb;
215dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
216dea3101eS 
217dea3101eS 	psli = &phba->sli;
218dea3101eS 	switch (topology) {
219dea3101eS 	case FLAGS_TOPOLOGY_MODE_LOOP_PT:
220dea3101eS 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
221dea3101eS 		mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
222dea3101eS 		break;
223dea3101eS 	case FLAGS_TOPOLOGY_MODE_PT_PT:
224dea3101eS 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
225dea3101eS 		break;
226dea3101eS 	case FLAGS_TOPOLOGY_MODE_LOOP:
227dea3101eS 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
228dea3101eS 		break;
229dea3101eS 	case FLAGS_TOPOLOGY_MODE_PT_LOOP:
230dea3101eS 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
231dea3101eS 		mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
232dea3101eS 		break;
233367c2713SJamie Wellnitz 	case FLAGS_LOCAL_LB:
234367c2713SJamie Wellnitz 		mb->un.varInitLnk.link_flags = FLAGS_LOCAL_LB;
235367c2713SJamie Wellnitz 		break;
236dea3101eS 	}
237dea3101eS 
2384b0b91d4SJames Smart 	/* Enable asynchronous ABTS responses from firmware */
2394b0b91d4SJames Smart 	mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT;
2404b0b91d4SJames Smart 
241dea3101eS 	/* NEW_FEATURE
242dea3101eS 	 * Setting up the link speed
243dea3101eS 	 */
244dea3101eS 	vpd = &phba->vpd;
245dea3101eS 	if (vpd->rev.feaLevelHigh >= 0x02){
246dea3101eS 		switch(linkspeed){
247dea3101eS 			case LINK_SPEED_1G:
248dea3101eS 			case LINK_SPEED_2G:
249dea3101eS 			case LINK_SPEED_4G:
250b87eab38SJames Smart 			case LINK_SPEED_8G:
251dea3101eS 				mb->un.varInitLnk.link_flags |=
252dea3101eS 							FLAGS_LINK_SPEED;
253dea3101eS 				mb->un.varInitLnk.link_speed = linkspeed;
254dea3101eS 			break;
255dea3101eS 			case LINK_SPEED_AUTO:
256dea3101eS 			default:
257dea3101eS 				mb->un.varInitLnk.link_speed =
258dea3101eS 							LINK_SPEED_AUTO;
259dea3101eS 			break;
260dea3101eS 		}
261dea3101eS 
262dea3101eS 	}
263dea3101eS 	else
264dea3101eS 		mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO;
265dea3101eS 
266dea3101eS 	mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK;
267dea3101eS 	mb->mbxOwner = OWN_HOST;
268dea3101eS 	mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA;
269dea3101eS 	return;
270dea3101eS }
271dea3101eS 
272dea3101eS /**********************************************/
273dea3101eS /*  lpfc_read_sparam  Issue a READ SPARAM     */
274dea3101eS /*                    mailbox command         */
275dea3101eS /**********************************************/
276dea3101eS int
27792d7f7b0SJames Smart lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
278dea3101eS {
279dea3101eS 	struct lpfc_dmabuf *mp;
280dea3101eS 	MAILBOX_t *mb;
281dea3101eS 	struct lpfc_sli *psli;
282dea3101eS 
283dea3101eS 	psli = &phba->sli;
284dea3101eS 	mb = &pmb->mb;
285dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
286dea3101eS 
287dea3101eS 	mb->mbxOwner = OWN_HOST;
288dea3101eS 
289dea3101eS 	/* Get a buffer to hold the HBAs Service Parameters */
290dea3101eS 
29198c9ea5cSJames Smart 	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
29298c9ea5cSJames Smart 	if (mp)
29398c9ea5cSJames Smart 		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
29498c9ea5cSJames Smart 	if (!mp || !mp->virt) {
295dea3101eS 		kfree(mp);
296dea3101eS 		mb->mbxCommand = MBX_READ_SPARM64;
297dea3101eS 		/* READ_SPARAM: no buffers */
298e8b62011SJames Smart 		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
299e8b62011SJames Smart 			        "0301 READ_SPARAM: no buffers\n");
30092d7f7b0SJames Smart 		return (1);
301dea3101eS 	}
302dea3101eS 	INIT_LIST_HEAD(&mp->list);
303dea3101eS 	mb->mbxCommand = MBX_READ_SPARM64;
304dea3101eS 	mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
305dea3101eS 	mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
306dea3101eS 	mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys);
30792d7f7b0SJames Smart 	mb->un.varRdSparm.vpi = vpi;
308dea3101eS 
309dea3101eS 	/* save address for completion */
310dea3101eS 	pmb->context1 = mp;
311dea3101eS 
31292d7f7b0SJames Smart 	return (0);
313dea3101eS }
314dea3101eS 
315dea3101eS /********************************************/
316dea3101eS /*  lpfc_unreg_did  Issue a UNREG_DID       */
317dea3101eS /*                  mailbox command         */
318dea3101eS /********************************************/
319dea3101eS void
32092d7f7b0SJames Smart lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did,
32192d7f7b0SJames Smart 	       LPFC_MBOXQ_t * pmb)
322dea3101eS {
323dea3101eS 	MAILBOX_t *mb;
324dea3101eS 
325dea3101eS 	mb = &pmb->mb;
326dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
327dea3101eS 
328dea3101eS 	mb->un.varUnregDID.did = did;
32992d7f7b0SJames Smart 	mb->un.varUnregDID.vpi = vpi;
330dea3101eS 
331dea3101eS 	mb->mbxCommand = MBX_UNREG_D_ID;
332dea3101eS 	mb->mbxOwner = OWN_HOST;
333dea3101eS 	return;
334dea3101eS }
335dea3101eS 
336dea3101eS /**********************************************/
337dea3101eS /*  lpfc_read_nv  Issue a READ CONFIG         */
338dea3101eS /*                mailbox command             */
339dea3101eS /**********************************************/
340dea3101eS void
341dea3101eS lpfc_read_config(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
342dea3101eS {
343dea3101eS 	MAILBOX_t *mb;
344dea3101eS 
345dea3101eS 	mb = &pmb->mb;
346dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
347dea3101eS 
348dea3101eS 	mb->mbxCommand = MBX_READ_CONFIG;
349dea3101eS 	mb->mbxOwner = OWN_HOST;
350dea3101eS 	return;
351dea3101eS }
352dea3101eS 
3537bb3b137SJamie Wellnitz /*************************************************/
3547bb3b137SJamie Wellnitz /*  lpfc_read_lnk_stat  Issue a READ LINK STATUS */
3557bb3b137SJamie Wellnitz /*                mailbox command                */
3567bb3b137SJamie Wellnitz /*************************************************/
3577bb3b137SJamie Wellnitz void
3587bb3b137SJamie Wellnitz lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
3597bb3b137SJamie Wellnitz {
3607bb3b137SJamie Wellnitz 	MAILBOX_t *mb;
3617bb3b137SJamie Wellnitz 
3627bb3b137SJamie Wellnitz 	mb = &pmb->mb;
3637bb3b137SJamie Wellnitz 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
3647bb3b137SJamie Wellnitz 
3657bb3b137SJamie Wellnitz 	mb->mbxCommand = MBX_READ_LNK_STAT;
3667bb3b137SJamie Wellnitz 	mb->mbxOwner = OWN_HOST;
3677bb3b137SJamie Wellnitz 	return;
3687bb3b137SJamie Wellnitz }
3697bb3b137SJamie Wellnitz 
370dea3101eS /********************************************/
371dea3101eS /*  lpfc_reg_login  Issue a REG_LOGIN       */
372dea3101eS /*                  mailbox command         */
373dea3101eS /********************************************/
374dea3101eS int
37592d7f7b0SJames Smart lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
37692d7f7b0SJames Smart 	       uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag)
377dea3101eS {
3782e0fef85SJames Smart 	MAILBOX_t *mb = &pmb->mb;
379dea3101eS 	uint8_t *sparam;
380dea3101eS 	struct lpfc_dmabuf *mp;
381dea3101eS 
382dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
383dea3101eS 
384dea3101eS 	mb->un.varRegLogin.rpi = 0;
38592d7f7b0SJames Smart 	mb->un.varRegLogin.vpi = vpi;
386dea3101eS 	mb->un.varRegLogin.did = did;
387dea3101eS 	mb->un.varWords[30] = flag;	/* Set flag to issue action on cmpl */
388dea3101eS 
389dea3101eS 	mb->mbxOwner = OWN_HOST;
390dea3101eS 
391dea3101eS 	/* Get a buffer to hold NPorts Service Parameters */
39298c9ea5cSJames Smart 	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
39398c9ea5cSJames Smart 	if (mp)
39498c9ea5cSJames Smart 		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
39598c9ea5cSJames Smart 	if (!mp || !mp->virt) {
396dea3101eS 		kfree(mp);
397dea3101eS 		mb->mbxCommand = MBX_REG_LOGIN64;
398dea3101eS 		/* REG_LOGIN: no buffers */
39992d7f7b0SJames Smart 		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
400e8b62011SJames Smart 				"0302 REG_LOGIN: no buffers, VPI:%d DID:x%x, "
401e8b62011SJames Smart 				"flag x%x\n", vpi, did, flag);
40292d7f7b0SJames Smart 		return (1);
403dea3101eS 	}
404dea3101eS 	INIT_LIST_HEAD(&mp->list);
405dea3101eS 	sparam = mp->virt;
406dea3101eS 
407dea3101eS 	/* Copy param's into a new buffer */
408dea3101eS 	memcpy(sparam, param, sizeof (struct serv_parm));
409dea3101eS 
410dea3101eS 	/* save address for completion */
411dea3101eS 	pmb->context1 = (uint8_t *) mp;
412dea3101eS 
413dea3101eS 	mb->mbxCommand = MBX_REG_LOGIN64;
414dea3101eS 	mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
415dea3101eS 	mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys);
416dea3101eS 	mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(mp->phys);
417dea3101eS 
41892d7f7b0SJames Smart 	return (0);
419dea3101eS }
420dea3101eS 
421dea3101eS /**********************************************/
422dea3101eS /*  lpfc_unreg_login  Issue a UNREG_LOGIN     */
423dea3101eS /*                    mailbox command         */
424dea3101eS /**********************************************/
425dea3101eS void
42692d7f7b0SJames Smart lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
42792d7f7b0SJames Smart 		 LPFC_MBOXQ_t * pmb)
428dea3101eS {
429dea3101eS 	MAILBOX_t *mb;
430dea3101eS 
431dea3101eS 	mb = &pmb->mb;
432dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
433dea3101eS 
434dea3101eS 	mb->un.varUnregLogin.rpi = (uint16_t) rpi;
435dea3101eS 	mb->un.varUnregLogin.rsvd1 = 0;
43692d7f7b0SJames Smart 	mb->un.varUnregLogin.vpi = vpi;
437dea3101eS 
438dea3101eS 	mb->mbxCommand = MBX_UNREG_LOGIN;
439dea3101eS 	mb->mbxOwner = OWN_HOST;
440dea3101eS 	return;
441dea3101eS }
442dea3101eS 
44392d7f7b0SJames Smart /**************************************************/
44492d7f7b0SJames Smart /*  lpfc_reg_vpi   Issue a REG_VPI                */
44592d7f7b0SJames Smart /*                    mailbox command             */
44692d7f7b0SJames Smart /**************************************************/
44792d7f7b0SJames Smart void
44892d7f7b0SJames Smart lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid,
44992d7f7b0SJames Smart 	     LPFC_MBOXQ_t *pmb)
45092d7f7b0SJames Smart {
45192d7f7b0SJames Smart 	MAILBOX_t *mb = &pmb->mb;
45292d7f7b0SJames Smart 
45392d7f7b0SJames Smart 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
45492d7f7b0SJames Smart 
45592d7f7b0SJames Smart 	mb->un.varRegVpi.vpi = vpi;
45692d7f7b0SJames Smart 	mb->un.varRegVpi.sid = sid;
45792d7f7b0SJames Smart 
45892d7f7b0SJames Smart 	mb->mbxCommand = MBX_REG_VPI;
45992d7f7b0SJames Smart 	mb->mbxOwner = OWN_HOST;
46092d7f7b0SJames Smart 	return;
46192d7f7b0SJames Smart 
46292d7f7b0SJames Smart }
46392d7f7b0SJames Smart 
46492d7f7b0SJames Smart /**************************************************/
46592d7f7b0SJames Smart /*  lpfc_unreg_vpi   Issue a UNREG_VNPI           */
46692d7f7b0SJames Smart /*                    mailbox command             */
46792d7f7b0SJames Smart /**************************************************/
46892d7f7b0SJames Smart void
46992d7f7b0SJames Smart lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb)
47092d7f7b0SJames Smart {
47192d7f7b0SJames Smart 	MAILBOX_t *mb = &pmb->mb;
47292d7f7b0SJames Smart 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
47392d7f7b0SJames Smart 
47492d7f7b0SJames Smart 	mb->un.varUnregVpi.vpi = vpi;
47592d7f7b0SJames Smart 
47692d7f7b0SJames Smart 	mb->mbxCommand = MBX_UNREG_VPI;
47792d7f7b0SJames Smart 	mb->mbxOwner = OWN_HOST;
47892d7f7b0SJames Smart 	return;
47992d7f7b0SJames Smart 
48092d7f7b0SJames Smart }
48192d7f7b0SJames Smart 
482dea3101eS static void
483dea3101eS lpfc_config_pcb_setup(struct lpfc_hba * phba)
484dea3101eS {
485dea3101eS 	struct lpfc_sli *psli = &phba->sli;
486dea3101eS 	struct lpfc_sli_ring *pring;
487dea3101eS 	PCB_t *pcbp = &phba->slim2p->pcb;
488dea3101eS 	dma_addr_t pdma_addr;
489dea3101eS 	uint32_t offset;
4902e0fef85SJames Smart 	uint32_t iocbCnt = 0;
491dea3101eS 	int i;
492dea3101eS 
493dea3101eS 	pcbp->maxRing = (psli->num_rings - 1);
494dea3101eS 
495dea3101eS 	for (i = 0; i < psli->num_rings; i++) {
496dea3101eS 		pring = &psli->ring[i];
4972e0fef85SJames Smart 
498ed957684SJames Smart 		pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE:
499ed957684SJames Smart 							SLI2_IOCB_CMD_SIZE;
500ed957684SJames Smart 		pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE:
501ed957684SJames Smart 							SLI2_IOCB_RSP_SIZE;
502dea3101eS 		/* A ring MUST have both cmd and rsp entries defined to be
503dea3101eS 		   valid */
504dea3101eS 		if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) {
505dea3101eS 			pcbp->rdsc[i].cmdEntries = 0;
506dea3101eS 			pcbp->rdsc[i].rspEntries = 0;
507dea3101eS 			pcbp->rdsc[i].cmdAddrHigh = 0;
508dea3101eS 			pcbp->rdsc[i].rspAddrHigh = 0;
509dea3101eS 			pcbp->rdsc[i].cmdAddrLow = 0;
510dea3101eS 			pcbp->rdsc[i].rspAddrLow = 0;
511dea3101eS 			pring->cmdringaddr = NULL;
512dea3101eS 			pring->rspringaddr = NULL;
513dea3101eS 			continue;
514dea3101eS 		}
515dea3101eS 		/* Command ring setup for ring */
516ed957684SJames Smart 		pring->cmdringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt];
517dea3101eS 		pcbp->rdsc[i].cmdEntries = pring->numCiocb;
518dea3101eS 
519dea3101eS 		offset = (uint8_t *) &phba->slim2p->IOCBs[iocbCnt] -
520dea3101eS 			 (uint8_t *) phba->slim2p;
521dea3101eS 		pdma_addr = phba->slim2p_mapping + offset;
522dea3101eS 		pcbp->rdsc[i].cmdAddrHigh = putPaddrHigh(pdma_addr);
523dea3101eS 		pcbp->rdsc[i].cmdAddrLow = putPaddrLow(pdma_addr);
524dea3101eS 		iocbCnt += pring->numCiocb;
525dea3101eS 
526dea3101eS 		/* Response ring setup for ring */
527ed957684SJames Smart 		pring->rspringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt];
528dea3101eS 
529dea3101eS 		pcbp->rdsc[i].rspEntries = pring->numRiocb;
530dea3101eS 		offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
531dea3101eS 			 (uint8_t *)phba->slim2p;
532dea3101eS 		pdma_addr = phba->slim2p_mapping + offset;
533dea3101eS 		pcbp->rdsc[i].rspAddrHigh = putPaddrHigh(pdma_addr);
534dea3101eS 		pcbp->rdsc[i].rspAddrLow = putPaddrLow(pdma_addr);
535dea3101eS 		iocbCnt += pring->numRiocb;
536dea3101eS 	}
537dea3101eS }
538dea3101eS 
539dea3101eS void
540dea3101eS lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
541dea3101eS {
5422e0fef85SJames Smart 	MAILBOX_t *mb = &pmb->mb;
543dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
544dea3101eS 	mb->un.varRdRev.cv = 1;
545ed957684SJames Smart 	mb->un.varRdRev.v3req = 1; /* Request SLI3 info */
546dea3101eS 	mb->mbxCommand = MBX_READ_REV;
547dea3101eS 	mb->mbxOwner = OWN_HOST;
548dea3101eS 	return;
549dea3101eS }
550dea3101eS 
551ed957684SJames Smart static void
552ed957684SJames Smart lpfc_build_hbq_profile2(struct config_hbq_var *hbqmb,
553ed957684SJames Smart 			struct lpfc_hbq_init  *hbq_desc)
554ed957684SJames Smart {
555ed957684SJames Smart 	hbqmb->profiles.profile2.seqlenbcnt = hbq_desc->seqlenbcnt;
556ed957684SJames Smart 	hbqmb->profiles.profile2.maxlen     = hbq_desc->maxlen;
557ed957684SJames Smart 	hbqmb->profiles.profile2.seqlenoff  = hbq_desc->seqlenoff;
558ed957684SJames Smart }
559ed957684SJames Smart 
560ed957684SJames Smart static void
561ed957684SJames Smart lpfc_build_hbq_profile3(struct config_hbq_var *hbqmb,
562ed957684SJames Smart 			struct lpfc_hbq_init  *hbq_desc)
563ed957684SJames Smart {
564ed957684SJames Smart 	hbqmb->profiles.profile3.seqlenbcnt = hbq_desc->seqlenbcnt;
565ed957684SJames Smart 	hbqmb->profiles.profile3.maxlen     = hbq_desc->maxlen;
566ed957684SJames Smart 	hbqmb->profiles.profile3.cmdcodeoff = hbq_desc->cmdcodeoff;
567ed957684SJames Smart 	hbqmb->profiles.profile3.seqlenoff  = hbq_desc->seqlenoff;
568ed957684SJames Smart 	memcpy(&hbqmb->profiles.profile3.cmdmatch, hbq_desc->cmdmatch,
569ed957684SJames Smart 	       sizeof(hbqmb->profiles.profile3.cmdmatch));
570ed957684SJames Smart }
571ed957684SJames Smart 
572ed957684SJames Smart static void
573ed957684SJames Smart lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb,
574ed957684SJames Smart 			struct lpfc_hbq_init  *hbq_desc)
575ed957684SJames Smart {
576ed957684SJames Smart 	hbqmb->profiles.profile5.seqlenbcnt = hbq_desc->seqlenbcnt;
577ed957684SJames Smart 	hbqmb->profiles.profile5.maxlen     = hbq_desc->maxlen;
578ed957684SJames Smart 	hbqmb->profiles.profile5.cmdcodeoff = hbq_desc->cmdcodeoff;
579ed957684SJames Smart 	hbqmb->profiles.profile5.seqlenoff  = hbq_desc->seqlenoff;
580ed957684SJames Smart 	memcpy(&hbqmb->profiles.profile5.cmdmatch, hbq_desc->cmdmatch,
581ed957684SJames Smart 	       sizeof(hbqmb->profiles.profile5.cmdmatch));
582ed957684SJames Smart }
583ed957684SJames Smart 
584ed957684SJames Smart void
58551ef4c26SJames Smart lpfc_config_hbq(struct lpfc_hba *phba, uint32_t id,
58651ef4c26SJames Smart 		 struct lpfc_hbq_init *hbq_desc,
587ed957684SJames Smart 		uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb)
588ed957684SJames Smart {
589ed957684SJames Smart 	int i;
590ed957684SJames Smart 	MAILBOX_t *mb = &pmb->mb;
591ed957684SJames Smart 	struct config_hbq_var *hbqmb = &mb->un.varCfgHbq;
592ed957684SJames Smart 
593ed957684SJames Smart 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
59451ef4c26SJames Smart 	hbqmb->hbqId = id;
595ed957684SJames Smart 	hbqmb->entry_count = hbq_desc->entry_count;   /* # entries in HBQ */
596ed957684SJames Smart 	hbqmb->recvNotify = hbq_desc->rn;             /* Receive
597ed957684SJames Smart 						       * Notification */
598ed957684SJames Smart 	hbqmb->numMask    = hbq_desc->mask_count;     /* # R_CTL/TYPE masks
599ed957684SJames Smart 						       * # in words 0-19 */
600ed957684SJames Smart 	hbqmb->profile    = hbq_desc->profile;	      /* Selection profile:
601ed957684SJames Smart 						       * 0 = all,
602ed957684SJames Smart 						       * 7 = logentry */
603ed957684SJames Smart 	hbqmb->ringMask   = hbq_desc->ring_mask;      /* Binds HBQ to a ring
604ed957684SJames Smart 						       * e.g. Ring0=b0001,
605ed957684SJames Smart 						       * ring2=b0100 */
606ed957684SJames Smart 	hbqmb->headerLen  = hbq_desc->headerLen;      /* 0 if not profile 4
607ed957684SJames Smart 						       * or 5 */
608ed957684SJames Smart 	hbqmb->logEntry   = hbq_desc->logEntry;       /* Set to 1 if this
609ed957684SJames Smart 						       * HBQ will be used
610ed957684SJames Smart 						       * for LogEntry
611ed957684SJames Smart 						       * buffers */
612ed957684SJames Smart 	hbqmb->hbqaddrLow = putPaddrLow(phba->hbqslimp.phys) +
613ed957684SJames Smart 		hbq_entry_index * sizeof(struct lpfc_hbq_entry);
614ed957684SJames Smart 	hbqmb->hbqaddrHigh = putPaddrHigh(phba->hbqslimp.phys);
615ed957684SJames Smart 
616ed957684SJames Smart 	mb->mbxCommand = MBX_CONFIG_HBQ;
617ed957684SJames Smart 	mb->mbxOwner = OWN_HOST;
618ed957684SJames Smart 
619ed957684SJames Smart 				/* Copy info for profiles 2,3,5. Other
620ed957684SJames Smart 				 * profiles this area is reserved
621ed957684SJames Smart 				 */
622ed957684SJames Smart 	if (hbq_desc->profile == 2)
623ed957684SJames Smart 		lpfc_build_hbq_profile2(hbqmb, hbq_desc);
624ed957684SJames Smart 	else if (hbq_desc->profile == 3)
625ed957684SJames Smart 		lpfc_build_hbq_profile3(hbqmb, hbq_desc);
626ed957684SJames Smart 	else if (hbq_desc->profile == 5)
627ed957684SJames Smart 		lpfc_build_hbq_profile5(hbqmb, hbq_desc);
628ed957684SJames Smart 
629ed957684SJames Smart 	/* Return if no rctl / type masks for this HBQ */
630ed957684SJames Smart 	if (!hbq_desc->mask_count)
631ed957684SJames Smart 		return;
632ed957684SJames Smart 
633ed957684SJames Smart 	/* Otherwise we setup specific rctl / type masks for this HBQ */
634ed957684SJames Smart 	for (i = 0; i < hbq_desc->mask_count; i++) {
635ed957684SJames Smart 		hbqmb->hbqMasks[i].tmatch = hbq_desc->hbqMasks[i].tmatch;
636ed957684SJames Smart 		hbqmb->hbqMasks[i].tmask  = hbq_desc->hbqMasks[i].tmask;
637ed957684SJames Smart 		hbqmb->hbqMasks[i].rctlmatch = hbq_desc->hbqMasks[i].rctlmatch;
638ed957684SJames Smart 		hbqmb->hbqMasks[i].rctlmask  = hbq_desc->hbqMasks[i].rctlmask;
639ed957684SJames Smart 	}
640ed957684SJames Smart 
641ed957684SJames Smart 	return;
642ed957684SJames Smart }
643ed957684SJames Smart 
64492d7f7b0SJames Smart 
64592d7f7b0SJames Smart 
646dea3101eS void
647dea3101eS lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
648dea3101eS {
649dea3101eS 	int i;
650dea3101eS 	MAILBOX_t *mb = &pmb->mb;
651dea3101eS 	struct lpfc_sli *psli;
652dea3101eS 	struct lpfc_sli_ring *pring;
653dea3101eS 
654dea3101eS 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
655dea3101eS 
656dea3101eS 	mb->un.varCfgRing.ring = ring;
657dea3101eS 	mb->un.varCfgRing.maxOrigXchg = 0;
658dea3101eS 	mb->un.varCfgRing.maxRespXchg = 0;
659dea3101eS 	mb->un.varCfgRing.recvNotify = 1;
660dea3101eS 
661dea3101eS 	psli = &phba->sli;
662dea3101eS 	pring = &psli->ring[ring];
663dea3101eS 	mb->un.varCfgRing.numMask = pring->num_mask;
664dea3101eS 	mb->mbxCommand = MBX_CONFIG_RING;
665dea3101eS 	mb->mbxOwner = OWN_HOST;
666dea3101eS 
667dea3101eS 	/* Is this ring configured for a specific profile */
668dea3101eS 	if (pring->prt[0].profile) {
669dea3101eS 		mb->un.varCfgRing.profile = pring->prt[0].profile;
670dea3101eS 		return;
671dea3101eS 	}
672dea3101eS 
673dea3101eS 	/* Otherwise we setup specific rctl / type masks for this ring */
674dea3101eS 	for (i = 0; i < pring->num_mask; i++) {
675dea3101eS 		mb->un.varCfgRing.rrRegs[i].rval = pring->prt[i].rctl;
676dea3101eS 		if (mb->un.varCfgRing.rrRegs[i].rval != FC_ELS_REQ)
677dea3101eS 			mb->un.varCfgRing.rrRegs[i].rmask = 0xff;
678dea3101eS 		else
679dea3101eS 			mb->un.varCfgRing.rrRegs[i].rmask = 0xfe;
680dea3101eS 		mb->un.varCfgRing.rrRegs[i].tval = pring->prt[i].type;
681dea3101eS 		mb->un.varCfgRing.rrRegs[i].tmask = 0xff;
682dea3101eS 	}
683dea3101eS 
684dea3101eS 	return;
685dea3101eS }
686dea3101eS 
687dea3101eS void
688dea3101eS lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
689dea3101eS {
690ed957684SJames Smart 	MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr;
691dea3101eS 	MAILBOX_t *mb = &pmb->mb;
692dea3101eS 	dma_addr_t pdma_addr;
693dea3101eS 	uint32_t bar_low, bar_high;
694dea3101eS 	size_t offset;
6954cc2da1dSJames.Smart@Emulex.Com 	struct lpfc_hgp hgp;
696f91b392cSJames.Smart@Emulex.Com 	int i;
697ed957684SJames Smart 	uint32_t pgp_offset;
698dea3101eS 
699dea3101eS 	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
700dea3101eS 	mb->mbxCommand = MBX_CONFIG_PORT;
701dea3101eS 	mb->mbxOwner = OWN_HOST;
702dea3101eS 
703dea3101eS 	mb->un.varCfgPort.pcbLen = sizeof(PCB_t);
704dea3101eS 
705dea3101eS 	offset = (uint8_t *)&phba->slim2p->pcb - (uint8_t *)phba->slim2p;
706dea3101eS 	pdma_addr = phba->slim2p_mapping + offset;
707dea3101eS 	mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr);
708dea3101eS 	mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr);
709dea3101eS 
710ed957684SJames Smart 	/* If HBA supports SLI=3 ask for it */
711ed957684SJames Smart 
71292d7f7b0SJames Smart 	if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
713ed957684SJames Smart 		mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
71451ef4c26SJames Smart 		mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
71578b2d852SJames Smart 		if (phba->max_vpi && phba->cfg_enable_npiv &&
71692d7f7b0SJames Smart 		    phba->vpd.sli3Feat.cmv) {
71792d7f7b0SJames Smart 			mb->un.varCfgPort.max_vpi = phba->max_vpi;
71892d7f7b0SJames Smart 			mb->un.varCfgPort.cmv = 1;
71992d7f7b0SJames Smart 			phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
72092d7f7b0SJames Smart 		} else
72192d7f7b0SJames Smart 			mb->un.varCfgPort.max_vpi = phba->max_vpi = 0;
72292d7f7b0SJames Smart 	} else
72392d7f7b0SJames Smart 		phba->sli_rev = 2;
72492d7f7b0SJames Smart 	mb->un.varCfgPort.sli_mode = phba->sli_rev;
725ed957684SJames Smart 
726dea3101eS 	/* Now setup pcb */
727dea3101eS 	phba->slim2p->pcb.type = TYPE_NATIVE_SLI2;
728dea3101eS 	phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2;
729dea3101eS 
730dea3101eS 	/* Setup Mailbox pointers */
731ed957684SJames Smart 	phba->slim2p->pcb.mailBoxSize = offsetof(MAILBOX_t, us) +
732ed957684SJames Smart 		sizeof(struct sli2_desc);
733dea3101eS 	offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p;
734dea3101eS 	pdma_addr = phba->slim2p_mapping + offset;
735dea3101eS 	phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr);
736dea3101eS 	phba->slim2p->pcb.mbAddrLow = putPaddrLow(pdma_addr);
737dea3101eS 
738dea3101eS 	/*
739dea3101eS 	 * Setup Host Group ring pointer.
740dea3101eS 	 *
741dea3101eS 	 * For efficiency reasons, the ring get/put pointers can be
742dea3101eS 	 * placed in adapter memory (SLIM) rather than in host memory.
743dea3101eS 	 * This allows firmware to avoid PCI reads/writes when updating
744dea3101eS 	 * and checking pointers.
745dea3101eS 	 *
746dea3101eS 	 * The firmware recognizes the use of SLIM memory by comparing
747dea3101eS 	 * the address of the get/put pointers structure with that of
748dea3101eS 	 * the SLIM BAR (BAR0).
749dea3101eS 	 *
750dea3101eS 	 * Caution: be sure to use the PCI config space value of BAR0/BAR1
751dea3101eS 	 * (the hardware's view of the base address), not the OS's
752dea3101eS 	 * value of pci_resource_start() as the OS value may be a cookie
753dea3101eS 	 * for ioremap/iomap.
754dea3101eS 	 */
755dea3101eS 
756dea3101eS 
757dea3101eS 	pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low);
758dea3101eS 	pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high);
759dea3101eS 
760ed957684SJames Smart 	/*
761ed957684SJames Smart 	 * Set up HGP - Port Memory
762ed957684SJames Smart 	 *
763ed957684SJames Smart 	 * The port expects the host get/put pointers to reside in memory
764ed957684SJames Smart 	 * following the "non-diagnostic" mode mailbox (32 words, 0x80 bytes)
765ed957684SJames Smart 	 * area of SLIM.  In SLI-2 mode, there's an additional 16 reserved
766ed957684SJames Smart 	 * words (0x40 bytes).  This area is not reserved if HBQs are
767ed957684SJames Smart 	 * configured in SLI-3.
768ed957684SJames Smart 	 *
769ed957684SJames Smart 	 * CR0Put    - SLI2(no HBQs) = 0xc0, With HBQs = 0x80
770ed957684SJames Smart 	 * RR0Get                      0xc4              0x84
771ed957684SJames Smart 	 * CR1Put                      0xc8              0x88
772ed957684SJames Smart 	 * RR1Get                      0xcc              0x8c
773ed957684SJames Smart 	 * CR2Put                      0xd0              0x90
774ed957684SJames Smart 	 * RR2Get                      0xd4              0x94
775ed957684SJames Smart 	 * CR3Put                      0xd8              0x98
776ed957684SJames Smart 	 * RR3Get                      0xdc              0x9c
777ed957684SJames Smart 	 *
778ed957684SJames Smart 	 * Reserved                    0xa0-0xbf
779ed957684SJames Smart 	 *    If HBQs configured:
780ed957684SJames Smart 	 *                         HBQ 0 Put ptr  0xc0
781ed957684SJames Smart 	 *                         HBQ 1 Put ptr  0xc4
782ed957684SJames Smart 	 *                         HBQ 2 Put ptr  0xc8
783ed957684SJames Smart 	 *                         ......
784ed957684SJames Smart 	 *                         HBQ(M-1)Put Pointer 0xc0+(M-1)*4
785ed957684SJames Smart 	 *
786ed957684SJames Smart 	 */
787ed957684SJames Smart 
788ed957684SJames Smart 	if (phba->sli_rev == 3) {
789ed957684SJames Smart 		phba->host_gp = &mb_slim->us.s3.host[0];
790ed957684SJames Smart 		phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
791ed957684SJames Smart 	} else {
792ed957684SJames Smart 		phba->host_gp = &mb_slim->us.s2.host[0];
793ed957684SJames Smart 		phba->hbq_put = NULL;
794ed957684SJames Smart 	}
795dea3101eS 
796dea3101eS 	/* mask off BAR0's flag bits 0 - 3 */
797dea3101eS 	phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
798ed957684SJames Smart 		(void __iomem *) phba->host_gp -
799ed957684SJames Smart 		(void __iomem *)phba->MBslimaddr;
800dea3101eS 	if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
801dea3101eS 		phba->slim2p->pcb.hgpAddrHigh = bar_high;
802dea3101eS 	else
803dea3101eS 		phba->slim2p->pcb.hgpAddrHigh = 0;
804dea3101eS 	/* write HGP data to SLIM at the required longword offset */
8054cc2da1dSJames.Smart@Emulex.Com 	memset(&hgp, 0, sizeof(struct lpfc_hgp));
806f91b392cSJames.Smart@Emulex.Com 
807f91b392cSJames.Smart@Emulex.Com 	for (i=0; i < phba->sli.num_rings; i++) {
808ed957684SJames Smart 		lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
809ed957684SJames Smart 				    sizeof(*phba->host_gp));
810f91b392cSJames.Smart@Emulex.Com 	}
811dea3101eS 
812dea3101eS 	/* Setup Port Group ring pointer */
813ed957684SJames Smart 	if (phba->sli_rev == 3)
814ed957684SJames Smart 		pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s3_pgp.port -
815dea3101eS 			(uint8_t *)phba->slim2p;
816ed957684SJames Smart 	else
817ed957684SJames Smart 		pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
818ed957684SJames Smart 			(uint8_t *)phba->slim2p;
819ed957684SJames Smart 
820ed957684SJames Smart 	pdma_addr = phba->slim2p_mapping + pgp_offset;
821dea3101eS 	phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr);
822dea3101eS 	phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr);
823ed957684SJames Smart 	phba->hbq_get = &phba->slim2p->mbx.us.s3_pgp.hbq_get[0];
824dea3101eS 
825dea3101eS 	/* Use callback routine to setp rings in the pcb */
826dea3101eS 	lpfc_config_pcb_setup(phba);
827dea3101eS 
828dea3101eS 	/* special handling for LC HBAs */
829dea3101eS 	if (lpfc_is_LC_HBA(phba->pcidev->device)) {
830dea3101eS 		uint32_t hbainit[5];
831dea3101eS 
832dea3101eS 		lpfc_hba_init(phba, hbainit);
833dea3101eS 
834dea3101eS 		memcpy(&mb->un.varCfgPort.hbainit, hbainit, 20);
835dea3101eS 	}
836dea3101eS 
837dea3101eS 	/* Swap PCB if needed */
838dea3101eS 	lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb,
839dea3101eS 			      sizeof(PCB_t));
840dea3101eS }
841dea3101eS 
842dea3101eS void
84341415862SJamie Wellnitz lpfc_kill_board(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
84441415862SJamie Wellnitz {
84541415862SJamie Wellnitz 	MAILBOX_t *mb = &pmb->mb;
84641415862SJamie Wellnitz 
84741415862SJamie Wellnitz 	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
84841415862SJamie Wellnitz 	mb->mbxCommand = MBX_KILL_BOARD;
84941415862SJamie Wellnitz 	mb->mbxOwner = OWN_HOST;
85041415862SJamie Wellnitz 	return;
85141415862SJamie Wellnitz }
85241415862SJamie Wellnitz 
85341415862SJamie Wellnitz void
854dea3101eS lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
855dea3101eS {
856dea3101eS 	struct lpfc_sli *psli;
857dea3101eS 
858dea3101eS 	psli = &phba->sli;
859dea3101eS 
860dea3101eS 	list_add_tail(&mbq->list, &psli->mboxq);
861dea3101eS 
862dea3101eS 	psli->mboxq_cnt++;
863dea3101eS 
864dea3101eS 	return;
865dea3101eS }
866dea3101eS 
867dea3101eS LPFC_MBOXQ_t *
868dea3101eS lpfc_mbox_get(struct lpfc_hba * phba)
869dea3101eS {
870dea3101eS 	LPFC_MBOXQ_t *mbq = NULL;
871dea3101eS 	struct lpfc_sli *psli = &phba->sli;
872dea3101eS 
8732e0fef85SJames Smart 	list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t, list);
87492d7f7b0SJames Smart 	if (mbq)
875dea3101eS 		psli->mboxq_cnt--;
876dea3101eS 
877dea3101eS 	return mbq;
878dea3101eS }
879a309a6b6SJames Smart 
88092d7f7b0SJames Smart void
88192d7f7b0SJames Smart lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
88292d7f7b0SJames Smart {
88392d7f7b0SJames Smart 	/* This function expects to be called from interupt context */
88492d7f7b0SJames Smart 	spin_lock(&phba->hbalock);
88592d7f7b0SJames Smart 	list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
88692d7f7b0SJames Smart 	spin_unlock(&phba->hbalock);
88792d7f7b0SJames Smart 	return;
88892d7f7b0SJames Smart }
88992d7f7b0SJames Smart 
890a309a6b6SJames Smart int
891a309a6b6SJames Smart lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
892a309a6b6SJames Smart {
893a309a6b6SJames Smart 	switch (cmd) {
894a309a6b6SJames Smart 	case MBX_WRITE_NV:	/* 0x03 */
895a309a6b6SJames Smart 	case MBX_UPDATE_CFG:	/* 0x1B */
896a309a6b6SJames Smart 	case MBX_DOWN_LOAD:	/* 0x1C */
897a309a6b6SJames Smart 	case MBX_DEL_LD_ENTRY:	/* 0x1D */
898a309a6b6SJames Smart 	case MBX_LOAD_AREA:	/* 0x81 */
899a309a6b6SJames Smart 	case MBX_FLASH_WR_ULA:  /* 0x98 */
900a309a6b6SJames Smart 	case MBX_LOAD_EXP_ROM:	/* 0x9C */
901a309a6b6SJames Smart 		return LPFC_MBOX_TMO_FLASH_CMD;
902a309a6b6SJames Smart 	}
903a309a6b6SJames Smart 	return LPFC_MBOX_TMO;
904a309a6b6SJames Smart }
905