blob: add6a3a6ef0de994ebf5405dd1c426e6eb1f294e [file] [log] [blame]
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001/*
2 * linux/drivers/message/fusion/mptfc.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04008 *
9 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040046#include <linux/module.h>
47#include <linux/kernel.h>
48#include <linux/init.h>
49#include <linux/errno.h>
50#include <linux/kdev_t.h>
51#include <linux/blkdev.h>
52#include <linux/delay.h> /* for mdelay */
53#include <linux/interrupt.h> /* needed for in_interrupt() proto */
54#include <linux/reboot.h> /* notifier code */
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040055#include <linux/workqueue.h>
Michael Reed05e8ec12006-01-13 14:31:54 -060056#include <linux/sort.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090057#include <linux/slab.h>
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040058
59#include <scsi/scsi.h>
60#include <scsi/scsi_cmnd.h>
61#include <scsi/scsi_device.h>
62#include <scsi/scsi_host.h>
63#include <scsi/scsi_tcq.h>
Michael Reed05e8ec12006-01-13 14:31:54 -060064#include <scsi/scsi_transport_fc.h>
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040065
66#include "mptbase.h"
67#include "mptscsih.h"
68
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT FC Host driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptfc"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040078
79/* Command line args */
Michael Reed05e8ec12006-01-13 14:31:54 -060080#define MPTFC_DEV_LOSS_TMO (60)
81static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO; /* reasonable default */
82module_param(mptfc_dev_loss_tmo, int, 0);
83MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "
84 " transport to wait for an rport to "
85 " return following a device loss event."
86 " Default=60.");
87
Eric Moore793955f2007-01-29 09:42:20 -070088/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
89#define MPTFC_MAX_LUN (16895)
90static int max_lun = MPTFC_MAX_LUN;
91module_param(max_lun, int, 0);
92MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
93
Prakash, Sathyaf606f572007-08-14 16:12:53 +053094static u8 mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static u8 mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
96static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040097
Michael Reed3bc7bf12006-01-25 18:05:18 -070098static int mptfc_target_alloc(struct scsi_target *starget);
99static int mptfc_slave_alloc(struct scsi_device *sdev);
Jeff Garzikf2812332010-11-16 02:10:29 -0500100static int mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt);
Michael Reed3bc7bf12006-01-25 18:05:18 -0700101static void mptfc_target_destroy(struct scsi_target *starget);
Michael Reed05e8ec12006-01-13 14:31:54 -0600102static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
Greg Kroah-Hartman47b1ea72012-12-21 15:04:26 -0800103static void mptfc_remove(struct pci_dev *pdev);
Michael Reed35508e42006-10-06 15:39:25 -0500104static int mptfc_abort(struct scsi_cmnd *SCpnt);
105static int mptfc_dev_reset(struct scsi_cmnd *SCpnt);
106static int mptfc_bus_reset(struct scsi_cmnd *SCpnt);
107static int mptfc_host_reset(struct scsi_cmnd *SCpnt);
Michael Reed05e8ec12006-01-13 14:31:54 -0600108
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400109static struct scsi_host_template mptfc_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700110 .module = THIS_MODULE,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400111 .proc_name = "mptfc",
Al Virocac19702013-03-31 01:42:38 -0400112 .show_info = mptscsih_show_info,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400113 .name = "MPT FC Host",
114 .info = mptscsih_info,
Michael Reed05e8ec12006-01-13 14:31:54 -0600115 .queuecommand = mptfc_qcmd,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700116 .target_alloc = mptfc_target_alloc,
Michael Reed05e8ec12006-01-13 14:31:54 -0600117 .slave_alloc = mptfc_slave_alloc,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400118 .slave_configure = mptscsih_slave_configure,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700119 .target_destroy = mptfc_target_destroy,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400120 .slave_destroy = mptscsih_slave_destroy,
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -0600121 .change_queue_depth = mptscsih_change_queue_depth,
Michael Reed35508e42006-10-06 15:39:25 -0500122 .eh_abort_handler = mptfc_abort,
123 .eh_device_reset_handler = mptfc_dev_reset,
124 .eh_bus_reset_handler = mptfc_bus_reset,
125 .eh_host_reset_handler = mptfc_host_reset,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400126 .bios_param = mptscsih_bios_param,
127 .can_queue = MPT_FC_CAN_QUEUE,
128 .this_id = -1,
129 .sg_tablesize = MPT_SCSI_SG_DEPTH,
130 .max_sectors = 8192,
131 .cmd_per_lun = 7,
132 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530133 .shost_attrs = mptscsih_host_attrs,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400134};
135
136/****************************************************************************
137 * Supported hardware
138 */
139
140static struct pci_device_id mptfc_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -0600141 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC909,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400142 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600143 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400144 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600145 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400146 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600147 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919X,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400148 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600149 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929X,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400150 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600151 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC939X,
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600152 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600153 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949X,
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600154 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600155 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E,
Moore, Eric6d5b0c32006-01-13 16:25:26 -0700156 PCI_ANY_ID, PCI_ANY_ID },
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +0530157 { PCI_VENDOR_ID_BROCADE, MPI_MANUFACTPAGE_DEVICEID_FC949E,
158 PCI_ANY_ID, PCI_ANY_ID },
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400159 {0} /* Terminating entry */
160};
161MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
162
Michael Reed05e8ec12006-01-13 14:31:54 -0600163static struct scsi_transport_template *mptfc_transport_template = NULL;
164
Adrian Bunk03fbcbc2006-01-25 02:00:52 +0100165static struct fc_function_template mptfc_transport_functions = {
Michael Reed05e8ec12006-01-13 14:31:54 -0600166 .dd_fcrport_size = 8,
167 .show_host_node_name = 1,
168 .show_host_port_name = 1,
169 .show_host_supported_classes = 1,
170 .show_host_port_id = 1,
171 .show_rport_supported_classes = 1,
172 .show_starget_node_name = 1,
173 .show_starget_port_name = 1,
174 .show_starget_port_id = 1,
175 .set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
176 .show_rport_dev_loss_tmo = 1,
Michael Reed5d947f22006-07-31 12:19:30 -0500177 .show_host_supported_speeds = 1,
178 .show_host_maxframe_size = 1,
179 .show_host_speed = 1,
180 .show_host_fabric_name = 1,
181 .show_host_port_type = 1,
182 .show_host_port_state = 1,
183 .show_host_symbolic_name = 1,
Michael Reed05e8ec12006-01-13 14:31:54 -0600184};
185
Michael Reed35508e42006-10-06 15:39:25 -0500186static int
187mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
188 int (*func)(struct scsi_cmnd *SCpnt),
189 const char *caller)
190{
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530191 MPT_SCSI_HOST *hd;
Michael Reed35508e42006-10-06 15:39:25 -0500192 struct scsi_device *sdev = SCpnt->device;
193 struct Scsi_Host *shost = sdev->host;
194 struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
195 unsigned long flags;
196 int ready;
Eric Mooree80b0022007-09-14 18:49:03 -0600197 MPT_ADAPTER *ioc;
Michael Reed03cb3822010-02-10 14:32:00 -0600198 int loops = 40; /* seconds */
Michael Reed35508e42006-10-06 15:39:25 -0500199
Eric Mooree7eae9f2007-09-29 10:15:59 -0600200 hd = shost_priv(SCpnt->device->host);
Eric Mooree80b0022007-09-14 18:49:03 -0600201 ioc = hd->ioc;
Michael Reed35508e42006-10-06 15:39:25 -0500202 spin_lock_irqsave(shost->host_lock, flags);
Michael Reed03cb3822010-02-10 14:32:00 -0600203 while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY
204 || (loops > 0 && ioc->active == 0)) {
Michael Reed35508e42006-10-06 15:39:25 -0500205 spin_unlock_irqrestore(shost->host_lock, flags);
Eric Mooree80b0022007-09-14 18:49:03 -0600206 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200207 "mptfc_block_error_handler.%d: %d:%llu, port status is "
Michael Reed03cb3822010-02-10 14:32:00 -0600208 "%x, active flag %d, deferring %s recovery.\n",
Eric Mooree7eae9f2007-09-29 10:15:59 -0600209 ioc->name, ioc->sh->host_no,
Michael Reed03cb3822010-02-10 14:32:00 -0600210 SCpnt->device->id, SCpnt->device->lun,
211 ready, ioc->active, caller));
Michael Reed35508e42006-10-06 15:39:25 -0500212 msleep(1000);
213 spin_lock_irqsave(shost->host_lock, flags);
Michael Reed03cb3822010-02-10 14:32:00 -0600214 loops --;
Michael Reed35508e42006-10-06 15:39:25 -0500215 }
216 spin_unlock_irqrestore(shost->host_lock, flags);
217
Michael Reed03cb3822010-02-10 14:32:00 -0600218 if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata
219 || ioc->active == 0) {
Eric Mooree80b0022007-09-14 18:49:03 -0600220 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200221 "%s.%d: %d:%llu, failing recovery, "
Michael Reed03cb3822010-02-10 14:32:00 -0600222 "port state %x, active %d, vdevice %p.\n", caller,
Eric Mooree7eae9f2007-09-29 10:15:59 -0600223 ioc->name, ioc->sh->host_no,
Eric Moore29dd3602007-09-14 18:46:51 -0600224 SCpnt->device->id, SCpnt->device->lun, ready,
Michael Reed03cb3822010-02-10 14:32:00 -0600225 ioc->active, SCpnt->device->hostdata));
Michael Reed35508e42006-10-06 15:39:25 -0500226 return FAILED;
227 }
Eric Mooree80b0022007-09-14 18:49:03 -0600228 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200229 "%s.%d: %d:%llu, executing recovery.\n", caller,
Eric Mooree7eae9f2007-09-29 10:15:59 -0600230 ioc->name, ioc->sh->host_no,
Eric Moore29dd3602007-09-14 18:46:51 -0600231 SCpnt->device->id, SCpnt->device->lun));
Michael Reed35508e42006-10-06 15:39:25 -0500232 return (*func)(SCpnt);
233}
234
235static int
236mptfc_abort(struct scsi_cmnd *SCpnt)
237{
238 return
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700239 mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__);
Michael Reed35508e42006-10-06 15:39:25 -0500240}
241
242static int
243mptfc_dev_reset(struct scsi_cmnd *SCpnt)
244{
245 return
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700246 mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__);
Michael Reed35508e42006-10-06 15:39:25 -0500247}
248
249static int
250mptfc_bus_reset(struct scsi_cmnd *SCpnt)
251{
252 return
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700253 mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__);
Michael Reed35508e42006-10-06 15:39:25 -0500254}
255
256static int
257mptfc_host_reset(struct scsi_cmnd *SCpnt)
258{
259 return
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700260 mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __func__);
Michael Reed35508e42006-10-06 15:39:25 -0500261}
262
Michael Reed05e8ec12006-01-13 14:31:54 -0600263static void
264mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
265{
266 if (timeout > 0)
267 rport->dev_loss_tmo = timeout;
268 else
269 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
270}
271
272static int
273mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
274{
275 FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
276 FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
277
278 if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
279 if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
280 return 0;
281 if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
282 return -1;
283 return 1;
284 }
285 if ((*aa)->CurrentBus < (*bb)->CurrentBus)
286 return -1;
287 return 1;
288}
289
290static int
291mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
292 void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
293{
294 ConfigPageHeader_t hdr;
295 CONFIGPARMS cfg;
296 FCDevicePage0_t *ppage0_alloc, *fc;
297 dma_addr_t page0_dma;
298 int data_sz;
299 int ii;
300
301 FCDevicePage0_t *p0_array=NULL, *p_p0;
302 FCDevicePage0_t **pp0_array=NULL, **p_pp0;
303
304 int rc = -ENOMEM;
305 U32 port_id = 0xffffff;
306 int num_targ = 0;
307 int max_bus = ioc->facts.MaxBuses;
Eric Moore793955f2007-01-29 09:42:20 -0700308 int max_targ;
Michael Reed05e8ec12006-01-13 14:31:54 -0600309
Eric Moore793955f2007-01-29 09:42:20 -0700310 max_targ = (ioc->facts.MaxDevices == 0) ? 256 : ioc->facts.MaxDevices;
Michael Reed05e8ec12006-01-13 14:31:54 -0600311
312 data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
313 p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL);
314 if (!p0_array)
315 goto out;
316
317 data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
318 p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
319 if (!pp0_array)
320 goto out;
321
322 do {
323 /* Get FC Device Page 0 header */
324 hdr.PageVersion = 0;
325 hdr.PageLength = 0;
326 hdr.PageNumber = 0;
327 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
328 cfg.cfghdr.hdr = &hdr;
329 cfg.physAddr = -1;
330 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
331 cfg.dir = 0;
332 cfg.pageAddr = port_id;
333 cfg.timeout = 0;
334
335 if ((rc = mpt_config(ioc, &cfg)) != 0)
336 break;
337
338 if (hdr.PageLength <= 0)
339 break;
340
341 data_sz = hdr.PageLength * 4;
342 ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
343 &page0_dma);
344 rc = -ENOMEM;
345 if (!ppage0_alloc)
346 break;
347
348 cfg.physAddr = page0_dma;
349 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
350
351 if ((rc = mpt_config(ioc, &cfg)) == 0) {
352 ppage0_alloc->PortIdentifier =
353 le32_to_cpu(ppage0_alloc->PortIdentifier);
354
355 ppage0_alloc->WWNN.Low =
356 le32_to_cpu(ppage0_alloc->WWNN.Low);
357
358 ppage0_alloc->WWNN.High =
359 le32_to_cpu(ppage0_alloc->WWNN.High);
360
361 ppage0_alloc->WWPN.Low =
362 le32_to_cpu(ppage0_alloc->WWPN.Low);
363
364 ppage0_alloc->WWPN.High =
365 le32_to_cpu(ppage0_alloc->WWPN.High);
366
367 ppage0_alloc->BBCredit =
368 le16_to_cpu(ppage0_alloc->BBCredit);
369
370 ppage0_alloc->MaxRxFrameSize =
371 le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
372
373 port_id = ppage0_alloc->PortIdentifier;
374 num_targ++;
375 *p_p0 = *ppage0_alloc; /* save data */
376 *p_pp0++ = p_p0++; /* save addr */
377 }
378 pci_free_consistent(ioc->pcidev, data_sz,
379 (u8 *) ppage0_alloc, page0_dma);
380 if (rc != 0)
381 break;
382
383 } while (port_id <= 0xff0000);
384
385 if (num_targ) {
386 /* sort array */
387 if (num_targ > 1)
388 sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
389 mptfc_FcDevPage0_cmp_func, NULL);
390 /* call caller's func for each targ */
391 for (ii = 0; ii < num_targ; ii++) {
392 fc = *(pp0_array+ii);
393 func(ioc, ioc_port, fc);
394 }
395 }
396
397 out:
Jesper Juhl8f760782006-06-27 02:55:06 -0700398 kfree(pp0_array);
399 kfree(p0_array);
Michael Reed05e8ec12006-01-13 14:31:54 -0600400 return rc;
401}
402
403static int
404mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
405{
406 /* not currently usable */
407 if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
408 MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
409 return -1;
410
411 if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
412 return -1;
413
414 if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
415 return -1;
416
417 /*
418 * board data structure already normalized to platform endianness
419 * shifted to avoid unaligned access on 64 bit architecture
420 */
421 rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
422 rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
423 rid->port_id = pg0->PortIdentifier;
424 rid->roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600425
426 return 0;
427}
428
429static void
430mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
431{
432 struct fc_rport_identifiers rport_ids;
433 struct fc_rport *rport;
434 struct mptfc_rport_info *ri;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700435 int new_ri = 1;
Moore, Eric65207fe2006-04-21 16:14:35 -0600436 u64 pn, nn;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700437 VirtTarget *vtarget;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500438 u32 roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600439
440 if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
441 return;
442
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500443 roles |= FC_RPORT_ROLE_FCP_TARGET;
444 if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
445 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
446
Michael Reed05e8ec12006-01-13 14:31:54 -0600447 /* scan list looking for a match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600448 list_for_each_entry(ri, &ioc->fc_rports, list) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700449 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
450 if (pn == rport_ids.port_name) { /* match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600451 list_move_tail(&ri->list, &ioc->fc_rports);
Michael Reed3bc7bf12006-01-25 18:05:18 -0700452 new_ri = 0;
Michael Reed05e8ec12006-01-13 14:31:54 -0600453 break;
454 }
455 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700456 if (new_ri) { /* allocate one */
Michael Reed05e8ec12006-01-13 14:31:54 -0600457 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
458 if (!ri)
459 return;
Michael Reed05e8ec12006-01-13 14:31:54 -0600460 list_add_tail(&ri->list, &ioc->fc_rports);
461 }
462
463 ri->pg0 = *pg0; /* add/update pg0 data */
464 ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
465
Michael Reed3bc7bf12006-01-25 18:05:18 -0700466 /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
Michael Reed05e8ec12006-01-13 14:31:54 -0600467 if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
468 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700469 rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
Michael Reed05e8ec12006-01-13 14:31:54 -0600470 if (rport) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700471 ri->rport = rport;
472 if (new_ri) /* may have been reset by user */
473 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
Michael Reed05e8ec12006-01-13 14:31:54 -0600474 /*
475 * if already mapped, remap here. If not mapped,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700476 * target_alloc will allocate vtarget and map,
Eric Moorea69de502007-09-14 18:48:19 -0600477 * slave_alloc will fill in vdevice from vtarget.
Michael Reed05e8ec12006-01-13 14:31:54 -0600478 */
Michael Reed3bc7bf12006-01-25 18:05:18 -0700479 if (ri->starget) {
480 vtarget = ri->starget->hostdata;
481 if (vtarget) {
Eric Moore793955f2007-01-29 09:42:20 -0700482 vtarget->id = pg0->CurrentTargetID;
483 vtarget->channel = pg0->CurrentBus;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +0530484 vtarget->deleted = 0;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700485 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600486 }
Moore, Eric65207fe2006-04-21 16:14:35 -0600487 *((struct mptfc_rport_info **)rport->dd_data) = ri;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500488 /* scan will be scheduled once rport becomes a target */
489 fc_remote_port_rolechg(rport,roles);
Moore, Eric65207fe2006-04-21 16:14:35 -0600490
491 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
492 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530493 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed3bc7bf12006-01-25 18:05:18 -0700494 "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600495 "rport tid %d, tmo %d\n",
Michael Reed3bc7bf12006-01-25 18:05:18 -0700496 ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700497 ioc->sh->host_no,
Michael Reed05e8ec12006-01-13 14:31:54 -0600498 pg0->PortIdentifier,
Moore, Eric65207fe2006-04-21 16:14:35 -0600499 (unsigned long long)nn,
500 (unsigned long long)pn,
Michael Reed05e8ec12006-01-13 14:31:54 -0600501 pg0->CurrentTargetID,
502 ri->rport->scsi_target_id,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700503 ri->rport->dev_loss_tmo));
Michael Reed05e8ec12006-01-13 14:31:54 -0600504 } else {
505 list_del(&ri->list);
506 kfree(ri);
507 ri = NULL;
508 }
509 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600510}
511
512/*
Michael Reed3bc7bf12006-01-25 18:05:18 -0700513 * OS entry point to allow for host driver to free allocated memory
514 * Called if no device present or device being unloaded
515 */
516static void
517mptfc_target_destroy(struct scsi_target *starget)
518{
519 struct fc_rport *rport;
520 struct mptfc_rport_info *ri;
521
522 rport = starget_to_rport(starget);
523 if (rport) {
524 ri = *((struct mptfc_rport_info **)rport->dd_data);
525 if (ri) /* better be! */
526 ri->starget = NULL;
527 }
Joe Lawrence5074b1b2014-06-25 17:06:02 -0400528 kfree(starget->hostdata);
Michael Reed3bc7bf12006-01-25 18:05:18 -0700529 starget->hostdata = NULL;
530}
531
532/*
533 * OS entry point to allow host driver to alloc memory
534 * for each scsi target. Called once per device the bus scan.
535 * Return non-zero if allocation fails.
536 */
537static int
538mptfc_target_alloc(struct scsi_target *starget)
539{
540 VirtTarget *vtarget;
541 struct fc_rport *rport;
542 struct mptfc_rport_info *ri;
543 int rc;
544
545 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
546 if (!vtarget)
547 return -ENOMEM;
548 starget->hostdata = vtarget;
549
550 rc = -ENODEV;
551 rport = starget_to_rport(starget);
552 if (rport) {
553 ri = *((struct mptfc_rport_info **)rport->dd_data);
554 if (ri) { /* better be! */
Eric Moore793955f2007-01-29 09:42:20 -0700555 vtarget->id = ri->pg0.CurrentTargetID;
556 vtarget->channel = ri->pg0.CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700557 ri->starget = starget;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700558 rc = 0;
559 }
560 }
561 if (rc != 0) {
562 kfree(vtarget);
563 starget->hostdata = NULL;
564 }
565
566 return rc;
567}
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530568/*
569 * mptfc_dump_lun_info
570 * @ioc
571 * @rport
572 * @sdev
573 *
574 */
575static void
576mptfc_dump_lun_info(MPT_ADAPTER *ioc, struct fc_rport *rport, struct scsi_device *sdev,
577 VirtTarget *vtarget)
578{
579 u64 nn, pn;
580 struct mptfc_rport_info *ri;
581
582 ri = *((struct mptfc_rport_info **)rport->dd_data);
583 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
584 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
585 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
586 "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
587 "CurrentTargetID %d, %x %llx %llx\n",
588 ioc->name,
589 sdev->host->host_no,
590 vtarget->num_luns,
591 sdev->id, ri->pg0.CurrentTargetID,
592 ri->pg0.PortIdentifier,
593 (unsigned long long)pn,
594 (unsigned long long)nn));
595}
596
Michael Reed3bc7bf12006-01-25 18:05:18 -0700597
598/*
Michael Reed05e8ec12006-01-13 14:31:54 -0600599 * OS entry point to allow host driver to alloc memory
600 * for each scsi device. Called once per device the bus scan.
601 * Return non-zero if allocation fails.
602 * Init memory once per LUN.
603 */
Adrian Bunk03fbcbc2006-01-25 02:00:52 +0100604static int
Michael Reed05e8ec12006-01-13 14:31:54 -0600605mptfc_slave_alloc(struct scsi_device *sdev)
606{
607 MPT_SCSI_HOST *hd;
608 VirtTarget *vtarget;
Eric Moorea69de502007-09-14 18:48:19 -0600609 VirtDevice *vdevice;
Michael Reed05e8ec12006-01-13 14:31:54 -0600610 struct scsi_target *starget;
611 struct fc_rport *rport;
Eric Mooree80b0022007-09-14 18:49:03 -0600612 MPT_ADAPTER *ioc;
Michael Reed05e8ec12006-01-13 14:31:54 -0600613
Moore, Eric65207fe2006-04-21 16:14:35 -0600614 starget = scsi_target(sdev);
615 rport = starget_to_rport(starget);
Michael Reed05e8ec12006-01-13 14:31:54 -0600616
617 if (!rport || fc_remote_port_chkready(rport))
618 return -ENXIO;
619
Eric Mooree7eae9f2007-09-29 10:15:59 -0600620 hd = shost_priv(sdev->host);
Eric Mooree80b0022007-09-14 18:49:03 -0600621 ioc = hd->ioc;
Michael Reed05e8ec12006-01-13 14:31:54 -0600622
Eric Moorea69de502007-09-14 18:48:19 -0600623 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
624 if (!vdevice) {
Michael Reed05e8ec12006-01-13 14:31:54 -0600625 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -0600626 ioc->name, sizeof(VirtDevice));
Michael Reed05e8ec12006-01-13 14:31:54 -0600627 return -ENOMEM;
628 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600629
Michael Reed05e8ec12006-01-13 14:31:54 -0600630
Eric Moorea69de502007-09-14 18:48:19 -0600631 sdev->hostdata = vdevice;
Michael Reed05e8ec12006-01-13 14:31:54 -0600632 vtarget = starget->hostdata;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700633
Michael Reed05e8ec12006-01-13 14:31:54 -0600634 if (vtarget->num_luns == 0) {
Eric Mooree80b0022007-09-14 18:49:03 -0600635 vtarget->ioc_id = ioc->id;
Eric Mooreba856d32006-07-11 17:34:01 -0600636 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
Michael Reed05e8ec12006-01-13 14:31:54 -0600637 }
638
Eric Moorea69de502007-09-14 18:48:19 -0600639 vdevice->vtarget = vtarget;
640 vdevice->lun = sdev->lun;
Michael Reed05e8ec12006-01-13 14:31:54 -0600641
Michael Reed05e8ec12006-01-13 14:31:54 -0600642 vtarget->num_luns++;
643
Moore, Eric65207fe2006-04-21 16:14:35 -0600644
Eric Mooree80b0022007-09-14 18:49:03 -0600645 mptfc_dump_lun_info(ioc, rport, sdev, vtarget);
Michael Reed05e8ec12006-01-13 14:31:54 -0600646
647 return 0;
648}
649
650static int
Matthew Wilcoxa48ac9e2014-03-27 16:40:36 -0400651mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
Michael Reed05e8ec12006-01-13 14:31:54 -0600652{
Michael Reed3bc7bf12006-01-25 18:05:18 -0700653 struct mptfc_rport_info *ri;
Michael Reed05e8ec12006-01-13 14:31:54 -0600654 struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
655 int err;
Eric Moorea69de502007-09-14 18:48:19 -0600656 VirtDevice *vdevice = SCpnt->device->hostdata;
Michael Reed05e8ec12006-01-13 14:31:54 -0600657
Eric Moorea69de502007-09-14 18:48:19 -0600658 if (!vdevice || !vdevice->vtarget) {
Eric Moore793955f2007-01-29 09:42:20 -0700659 SCpnt->result = DID_NO_CONNECT << 16;
Matthew Wilcoxa48ac9e2014-03-27 16:40:36 -0400660 SCpnt->scsi_done(SCpnt);
Michael Reed05e8ec12006-01-13 14:31:54 -0600661 return 0;
662 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700663
Eric Moore793955f2007-01-29 09:42:20 -0700664 err = fc_remote_port_chkready(rport);
665 if (unlikely(err)) {
666 SCpnt->result = err;
Matthew Wilcoxa48ac9e2014-03-27 16:40:36 -0400667 SCpnt->scsi_done(SCpnt);
Michael Reed35508e42006-10-06 15:39:25 -0500668 return 0;
669 }
670
Moore, Eric65207fe2006-04-21 16:14:35 -0600671 /* dd_data is null until finished adding target */
672 ri = *((struct mptfc_rport_info **)rport->dd_data);
673 if (unlikely(!ri)) {
Moore, Eric65207fe2006-04-21 16:14:35 -0600674 SCpnt->result = DID_IMM_RETRY << 16;
Matthew Wilcoxa48ac9e2014-03-27 16:40:36 -0400675 SCpnt->scsi_done(SCpnt);
Moore, Eric65207fe2006-04-21 16:14:35 -0600676 return 0;
677 }
678
Matthew Wilcoxa48ac9e2014-03-27 16:40:36 -0400679 return mptscsih_qcmd(SCpnt);
Michael Reed05e8ec12006-01-13 14:31:54 -0600680}
681
Michael Reed80d3ac72006-05-24 15:07:09 -0500682/*
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +0530683 * mptfc_display_port_link_speed - displaying link speed
684 * @ioc: Pointer to MPT_ADAPTER structure
685 * @portnum: IOC Port number
686 * @pp0dest: port page0 data payload
687 *
688 */
689static void
690mptfc_display_port_link_speed(MPT_ADAPTER *ioc, int portnum, FCPortPage0_t *pp0dest)
691{
692 u8 old_speed, new_speed, state;
693 char *old, *new;
694
695 if (portnum >= 2)
696 return;
697
698 old_speed = ioc->fc_link_speed[portnum];
699 new_speed = pp0dest->CurrentSpeed;
700 state = pp0dest->PortState;
701
702 if (state != MPI_FCPORTPAGE0_PORTSTATE_OFFLINE &&
703 new_speed != MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN) {
704
705 old = old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
706 old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
707 old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
708 "Unknown";
709 new = new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
710 new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
711 new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
712 "Unknown";
713 if (old_speed == 0)
714 printk(MYIOC_s_NOTE_FMT
715 "FC Link Established, Speed = %s\n",
716 ioc->name, new);
717 else if (old_speed != new_speed)
718 printk(MYIOC_s_WARN_FMT
719 "FC Link Speed Change, Old Speed = %s, New Speed = %s\n",
720 ioc->name, old, new);
721
722 ioc->fc_link_speed[portnum] = new_speed;
723 }
724}
725
726/*
Michael Reed80d3ac72006-05-24 15:07:09 -0500727 * mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
728 * @ioc: Pointer to MPT_ADAPTER structure
729 * @portnum: IOC Port number
730 *
731 * Return: 0 for success
732 * -ENOMEM if no memory available
733 * -EPERM if not allowed due to ISR context
734 * -EAGAIN if no msg frames currently available
735 * -EFAULT for non-successful reply or no reply (timeout)
736 * -EINVAL portnum arg out of range (hardwired to two elements)
737 */
738static int
739mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
740{
741 ConfigPageHeader_t hdr;
742 CONFIGPARMS cfg;
743 FCPortPage0_t *ppage0_alloc;
744 FCPortPage0_t *pp0dest;
745 dma_addr_t page0_dma;
746 int data_sz;
747 int copy_sz;
748 int rc;
749 int count = 400;
750
751 if (portnum > 1)
752 return -EINVAL;
753
754 /* Get FCPort Page 0 header */
755 hdr.PageVersion = 0;
756 hdr.PageLength = 0;
757 hdr.PageNumber = 0;
758 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
759 cfg.cfghdr.hdr = &hdr;
760 cfg.physAddr = -1;
761 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
762 cfg.dir = 0;
763 cfg.pageAddr = portnum;
764 cfg.timeout = 0;
765
766 if ((rc = mpt_config(ioc, &cfg)) != 0)
767 return rc;
768
769 if (hdr.PageLength == 0)
770 return 0;
771
772 data_sz = hdr.PageLength * 4;
773 rc = -ENOMEM;
774 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
775 if (ppage0_alloc) {
776
777 try_again:
778 memset((u8 *)ppage0_alloc, 0, data_sz);
779 cfg.physAddr = page0_dma;
780 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
781
782 if ((rc = mpt_config(ioc, &cfg)) == 0) {
783 /* save the data */
784 pp0dest = &ioc->fc_port_page0[portnum];
785 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
786 memcpy(pp0dest, ppage0_alloc, copy_sz);
787
788 /*
789 * Normalize endianness of structure data,
790 * by byte-swapping all > 1 byte fields!
791 */
792 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
793 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
794 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
795 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
796 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
797 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
798 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
799 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
800 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
801 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
802 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
803 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
804 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
805 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
806 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
807 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
808
809 /*
810 * if still doing discovery,
811 * hang loose a while until finished
812 */
Michael Reed77d88ee2006-07-31 12:19:40 -0500813 if ((pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) ||
814 (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE &&
815 (pp0dest->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK)
816 == MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT)) {
Michael Reed80d3ac72006-05-24 15:07:09 -0500817 if (count-- > 0) {
Michael Reedd6be06c2006-05-24 15:07:57 -0500818 msleep(100);
Michael Reed80d3ac72006-05-24 15:07:09 -0500819 goto try_again;
820 }
821 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
822 " complete.\n",
823 ioc->name);
824 }
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +0530825 mptfc_display_port_link_speed(ioc, portnum, pp0dest);
Michael Reed80d3ac72006-05-24 15:07:09 -0500826 }
827
828 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
829 }
830
831 return rc;
832}
833
Michael Reedca2f9382006-05-24 15:07:24 -0500834static int
835mptfc_WriteFcPortPage1(MPT_ADAPTER *ioc, int portnum)
836{
837 ConfigPageHeader_t hdr;
838 CONFIGPARMS cfg;
839 int rc;
840
841 if (portnum > 1)
842 return -EINVAL;
843
844 if (!(ioc->fc_data.fc_port_page1[portnum].data))
845 return -EINVAL;
846
847 /* get fcport page 1 header */
848 hdr.PageVersion = 0;
849 hdr.PageLength = 0;
850 hdr.PageNumber = 1;
851 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
852 cfg.cfghdr.hdr = &hdr;
853 cfg.physAddr = -1;
854 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
855 cfg.dir = 0;
856 cfg.pageAddr = portnum;
857 cfg.timeout = 0;
858
859 if ((rc = mpt_config(ioc, &cfg)) != 0)
860 return rc;
861
862 if (hdr.PageLength == 0)
863 return -ENODEV;
864
865 if (hdr.PageLength*4 != ioc->fc_data.fc_port_page1[portnum].pg_sz)
866 return -EINVAL;
867
868 cfg.physAddr = ioc->fc_data.fc_port_page1[portnum].dma;
869 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
870 cfg.dir = 1;
871
872 rc = mpt_config(ioc, &cfg);
873
874 return rc;
875}
876
877static int
878mptfc_GetFcPortPage1(MPT_ADAPTER *ioc, int portnum)
879{
880 ConfigPageHeader_t hdr;
881 CONFIGPARMS cfg;
882 FCPortPage1_t *page1_alloc;
883 dma_addr_t page1_dma;
884 int data_sz;
885 int rc;
886
887 if (portnum > 1)
888 return -EINVAL;
889
890 /* get fcport page 1 header */
891 hdr.PageVersion = 0;
892 hdr.PageLength = 0;
893 hdr.PageNumber = 1;
894 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
895 cfg.cfghdr.hdr = &hdr;
896 cfg.physAddr = -1;
897 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
898 cfg.dir = 0;
899 cfg.pageAddr = portnum;
900 cfg.timeout = 0;
901
902 if ((rc = mpt_config(ioc, &cfg)) != 0)
903 return rc;
904
905 if (hdr.PageLength == 0)
906 return -ENODEV;
907
908start_over:
909
910 if (ioc->fc_data.fc_port_page1[portnum].data == NULL) {
911 data_sz = hdr.PageLength * 4;
912 if (data_sz < sizeof(FCPortPage1_t))
913 data_sz = sizeof(FCPortPage1_t);
914
915 page1_alloc = (FCPortPage1_t *) pci_alloc_consistent(ioc->pcidev,
916 data_sz,
917 &page1_dma);
918 if (!page1_alloc)
919 return -ENOMEM;
920 }
921 else {
922 page1_alloc = ioc->fc_data.fc_port_page1[portnum].data;
923 page1_dma = ioc->fc_data.fc_port_page1[portnum].dma;
924 data_sz = ioc->fc_data.fc_port_page1[portnum].pg_sz;
925 if (hdr.PageLength * 4 > data_sz) {
926 ioc->fc_data.fc_port_page1[portnum].data = NULL;
927 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
928 page1_alloc, page1_dma);
929 goto start_over;
930 }
931 }
932
933 memset(page1_alloc,0,data_sz);
934
935 cfg.physAddr = page1_dma;
936 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
937
938 if ((rc = mpt_config(ioc, &cfg)) == 0) {
939 ioc->fc_data.fc_port_page1[portnum].data = page1_alloc;
940 ioc->fc_data.fc_port_page1[portnum].pg_sz = data_sz;
941 ioc->fc_data.fc_port_page1[portnum].dma = page1_dma;
942 }
943 else {
944 ioc->fc_data.fc_port_page1[portnum].data = NULL;
945 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
946 page1_alloc, page1_dma);
947 }
948
949 return rc;
950}
951
952static void
953mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
954{
955 int ii;
956 FCPortPage1_t *pp1;
957
958 #define MPTFC_FW_DEVICE_TIMEOUT (1)
959 #define MPTFC_FW_IO_PEND_TIMEOUT (1)
960 #define ON_FLAGS (MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY)
961 #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)
962
963 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
964 if (mptfc_GetFcPortPage1(ioc, ii) != 0)
965 continue;
966 pp1 = ioc->fc_data.fc_port_page1[ii].data;
967 if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)
968 && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)
969 && ((pp1->Flags & ON_FLAGS) == ON_FLAGS)
970 && ((pp1->Flags & OFF_FLAGS) == 0))
971 continue;
972 pp1->InitiatorDeviceTimeout = MPTFC_FW_DEVICE_TIMEOUT;
973 pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT;
974 pp1->Flags &= ~OFF_FLAGS;
975 pp1->Flags |= ON_FLAGS;
976 mptfc_WriteFcPortPage1(ioc, ii);
977 }
978}
979
980
Michael Reed05e8ec12006-01-13 14:31:54 -0600981static void
982mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
983{
Michael Reed5d947f22006-07-31 12:19:30 -0500984 unsigned class = 0;
985 unsigned cos = 0;
986 unsigned speed;
987 unsigned port_type;
988 unsigned port_state;
989 FCPortPage0_t *pp0;
990 struct Scsi_Host *sh;
991 char *sn;
Michael Reed05e8ec12006-01-13 14:31:54 -0600992
993 /* don't know what to do as only one scsi (fc) host was allocated */
994 if (portnum != 0)
995 return;
996
Michael Reed5d947f22006-07-31 12:19:30 -0500997 pp0 = &ioc->fc_port_page0[portnum];
998 sh = ioc->sh;
999
1000 sn = fc_host_symbolic_name(sh);
1001 snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",
1002 ioc->prod_name,
1003 MPT_FW_REV_MAGIC_ID_STRING,
1004 ioc->facts.FWVersion.Word);
1005
1006 fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;
1007
1008 fc_host_maxframe_size(sh) = pp0->MaxFrameSize;
1009
1010 fc_host_node_name(sh) =
1011 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
1012
1013 fc_host_port_name(sh) =
1014 (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;
1015
1016 fc_host_port_id(sh) = pp0->PortIdentifier;
1017
1018 class = pp0->SupportedServiceClass;
Michael Reed05e8ec12006-01-13 14:31:54 -06001019 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
1020 cos |= FC_COS_CLASS1;
1021 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
1022 cos |= FC_COS_CLASS2;
1023 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
1024 cos |= FC_COS_CLASS3;
Michael Reed5d947f22006-07-31 12:19:30 -05001025 fc_host_supported_classes(sh) = cos;
Michael Reed05e8ec12006-01-13 14:31:54 -06001026
Michael Reed5d947f22006-07-31 12:19:30 -05001027 if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)
1028 speed = FC_PORTSPEED_1GBIT;
1029 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)
1030 speed = FC_PORTSPEED_2GBIT;
1031 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)
1032 speed = FC_PORTSPEED_4GBIT;
1033 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)
1034 speed = FC_PORTSPEED_10GBIT;
1035 else
1036 speed = FC_PORTSPEED_UNKNOWN;
1037 fc_host_speed(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -06001038
Michael Reed5d947f22006-07-31 12:19:30 -05001039 speed = 0;
1040 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)
1041 speed |= FC_PORTSPEED_1GBIT;
1042 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
1043 speed |= FC_PORTSPEED_2GBIT;
1044 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
1045 speed |= FC_PORTSPEED_4GBIT;
1046 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
1047 speed |= FC_PORTSPEED_10GBIT;
1048 fc_host_supported_speeds(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -06001049
Michael Reed5d947f22006-07-31 12:19:30 -05001050 port_state = FC_PORTSTATE_UNKNOWN;
1051 if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)
1052 port_state = FC_PORTSTATE_ONLINE;
1053 else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)
1054 port_state = FC_PORTSTATE_LINKDOWN;
1055 fc_host_port_state(sh) = port_state;
Michael Reed05e8ec12006-01-13 14:31:54 -06001056
Michael Reed5d947f22006-07-31 12:19:30 -05001057 port_type = FC_PORTTYPE_UNKNOWN;
1058 if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)
1059 port_type = FC_PORTTYPE_PTP;
1060 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)
1061 port_type = FC_PORTTYPE_LPORT;
1062 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)
1063 port_type = FC_PORTTYPE_NLPORT;
1064 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)
1065 port_type = FC_PORTTYPE_NPORT;
1066 fc_host_port_type(sh) = port_type;
Michael Reed05e8ec12006-01-13 14:31:54 -06001067
Michael Reed5d947f22006-07-31 12:19:30 -05001068 fc_host_fabric_name(sh) =
1069 (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?
1070 (u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :
1071 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
1072
Michael Reed05e8ec12006-01-13 14:31:54 -06001073}
1074
1075static void
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +05301076mptfc_link_status_change(struct work_struct *work)
1077{
1078 MPT_ADAPTER *ioc =
1079 container_of(work, MPT_ADAPTER, fc_rescan_work);
1080 int ii;
1081
1082 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++)
1083 (void) mptfc_GetFcPortPage0(ioc, ii);
1084
1085}
1086
1087static void
David Howellsc4028952006-11-22 14:57:56 +00001088mptfc_setup_reset(struct work_struct *work)
Michael Reed419835e2006-05-24 15:07:40 -05001089{
David Howellsc4028952006-11-22 14:57:56 +00001090 MPT_ADAPTER *ioc =
1091 container_of(work, MPT_ADAPTER, fc_setup_reset_work);
Michael Reed419835e2006-05-24 15:07:40 -05001092 u64 pn;
1093 struct mptfc_rport_info *ri;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301094 struct scsi_target *starget;
1095 VirtTarget *vtarget;
Michael Reed419835e2006-05-24 15:07:40 -05001096
1097 /* reset about to happen, delete (block) all rports */
1098 list_for_each_entry(ri, &ioc->fc_rports, list) {
1099 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1100 ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
1101 fc_remote_port_delete(ri->rport); /* won't sleep */
1102 ri->rport = NULL;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301103 starget = ri->starget;
1104 if (starget) {
1105 vtarget = starget->hostdata;
1106 if (vtarget)
1107 vtarget->deleted = 1;
1108 }
Michael Reed419835e2006-05-24 15:07:40 -05001109
1110 pn = (u64)ri->pg0.WWPN.High << 32 |
1111 (u64)ri->pg0.WWPN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301112 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed419835e2006-05-24 15:07:40 -05001113 "mptfc_setup_reset.%d: %llx deleted\n",
1114 ioc->name,
1115 ioc->sh->host_no,
1116 (unsigned long long)pn));
1117 }
1118 }
1119}
1120
1121static void
David Howellsc4028952006-11-22 14:57:56 +00001122mptfc_rescan_devices(struct work_struct *work)
Michael Reed05e8ec12006-01-13 14:31:54 -06001123{
David Howellsc4028952006-11-22 14:57:56 +00001124 MPT_ADAPTER *ioc =
1125 container_of(work, MPT_ADAPTER, fc_rescan_work);
Michael Reed05e8ec12006-01-13 14:31:54 -06001126 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001127 u64 pn;
Michael Reed05e8ec12006-01-13 14:31:54 -06001128 struct mptfc_rport_info *ri;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301129 struct scsi_target *starget;
1130 VirtTarget *vtarget;
Michael Reed05e8ec12006-01-13 14:31:54 -06001131
Michael Reed3a0c56d2006-07-31 12:19:50 -05001132 /* start by tagging all ports as missing */
1133 list_for_each_entry(ri, &ioc->fc_rports, list) {
1134 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1135 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
Michael Reed05e8ec12006-01-13 14:31:54 -06001136 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001137 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001138
Michael Reed3a0c56d2006-07-31 12:19:50 -05001139 /*
1140 * now rescan devices known to adapter,
1141 * will reregister existing rports
1142 */
1143 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1144 (void) mptfc_GetFcPortPage0(ioc, ii);
1145 mptfc_init_host_attr(ioc, ii); /* refresh */
1146 mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev);
1147 }
1148
1149 /* delete devices still missing */
1150 list_for_each_entry(ri, &ioc->fc_rports, list) {
1151 /* if newly missing, delete it */
1152 if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
1153
1154 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
1155 MPT_RPORT_INFO_FLAGS_MISSING);
1156 fc_remote_port_delete(ri->rport); /* won't sleep */
1157 ri->rport = NULL;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301158 starget = ri->starget;
1159 if (starget) {
1160 vtarget = starget->hostdata;
1161 if (vtarget)
1162 vtarget->deleted = 1;
1163 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001164
1165 pn = (u64)ri->pg0.WWPN.High << 32 |
1166 (u64)ri->pg0.WWPN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301167 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed3a0c56d2006-07-31 12:19:50 -05001168 "mptfc_rescan.%d: %llx deleted\n",
1169 ioc->name,
1170 ioc->sh->host_no,
1171 (unsigned long long)pn));
Michael Reed05e8ec12006-01-13 14:31:54 -06001172 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001173 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001174}
1175
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001176static int
1177mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1178{
1179 struct Scsi_Host *sh;
1180 MPT_SCSI_HOST *hd;
1181 MPT_ADAPTER *ioc;
1182 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001183 int ii;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001184 int numSGE = 0;
1185 int scale;
1186 int ioc_cap;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001187 int error=0;
1188 int r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001189
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001190 if ((r = mpt_attach(pdev,id)) != 0)
1191 return r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001192
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001193 ioc = pci_get_drvdata(pdev);
Moore, Eric Dean d335cc32005-04-30 17:09:38 -05001194 ioc->DoneCtx = mptfcDoneCtx;
1195 ioc->TaskCtx = mptfcTaskCtx;
1196 ioc->InternalCtx = mptfcInternalCtx;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001197
1198 /* Added sanity check on readiness of the MPT adapter.
1199 */
1200 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1201 printk(MYIOC_s_WARN_FMT
1202 "Skipping because it's not operational!\n",
1203 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001204 error = -ENODEV;
1205 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001206 }
1207
1208 if (!ioc->active) {
1209 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1210 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001211 error = -ENODEV;
1212 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001213 }
1214
1215 /* Sanity check - ensure at least 1 port is INITIATOR capable
1216 */
1217 ioc_cap = 0;
1218 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1219 if (ioc->pfacts[ii].ProtocolFlags &
1220 MPI_PORTFACTS_PROTOCOL_INITIATOR)
1221 ioc_cap ++;
1222 }
1223
1224 if (!ioc_cap) {
1225 printk(MYIOC_s_WARN_FMT
1226 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1227 ioc->name, ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001228 return 0;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001229 }
1230
1231 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
1232
1233 if (!sh) {
1234 printk(MYIOC_s_WARN_FMT
1235 "Unable to register controller with SCSI subsystem\n",
1236 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001237 error = -1;
1238 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001239 }
1240
Michael Reed80d3ac72006-05-24 15:07:09 -05001241 spin_lock_init(&ioc->fc_rescan_work_lock);
David Howellsc4028952006-11-22 14:57:56 +00001242 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
1243 INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +05301244 INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change);
Michael Reed05e8ec12006-01-13 14:31:54 -06001245
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001246 spin_lock_irqsave(&ioc->FreeQlock, flags);
1247
1248 /* Attach the SCSI Host to the IOC structure
1249 */
1250 ioc->sh = sh;
1251
1252 sh->io_port = 0;
1253 sh->n_io_port = 0;
1254 sh->irq = 0;
1255
1256 /* set 16 byte cdb's */
1257 sh->max_cmd_len = 16;
1258
Eric Moore793955f2007-01-29 09:42:20 -07001259 sh->max_id = ioc->pfacts->MaxDevices;
1260 sh->max_lun = max_lun;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001261
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001262 /* Required entry.
1263 */
1264 sh->unique_id = ioc->id;
1265
1266 /* Verify that we won't exceed the maximum
1267 * number of chain buffers
1268 * We can optimize: ZZ = req_sz/sizeof(SGE)
1269 * For 32bit SGE's:
1270 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1271 * + (req_sz - 64)/sizeof(SGE)
1272 * A slightly different algorithm is required for
1273 * 64bit SGEs.
1274 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301275 scale = ioc->req_sz/ioc->SGE_size;
1276 if (ioc->sg_addr_size == sizeof(u64)) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001277 numSGE = (scale - 1) *
1278 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301279 (ioc->req_sz - 60) / ioc->SGE_size;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001280 } else {
1281 numSGE = 1 + (scale - 1) *
1282 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301283 (ioc->req_sz - 64) / ioc->SGE_size;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001284 }
1285
1286 if (numSGE < sh->sg_tablesize) {
1287 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301288 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001289 "Resetting sg_tablesize to %d from %d\n",
1290 ioc->name, numSGE, sh->sg_tablesize));
1291 sh->sg_tablesize = numSGE;
1292 }
1293
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001294 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1295
Eric Mooree7eae9f2007-09-29 10:15:59 -06001296 hd = shost_priv(sh);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001297 hd->ioc = ioc;
1298
1299 /* SCSI needs scsi_cmnd lookup table!
1300 * (with size equal to req_depth*PtrSz!)
1301 */
Eric Mooree8206382007-09-29 10:16:53 -06001302 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
1303 if (!ioc->ScsiLookup) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001304 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001305 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001306 }
Eric Mooree8206382007-09-29 10:16:53 -06001307 spin_lock_init(&ioc->scsi_lookup_lock);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001308
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301309 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06001310 ioc->name, ioc->ScsiLookup));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001311
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001312 hd->last_queue_full = 0;
1313
Michael Reed05e8ec12006-01-13 14:31:54 -06001314 sh->transportt = mptfc_transport_template;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001315 error = scsi_add_host (sh, &ioc->pcidev->dev);
1316 if(error) {
Eric Moore29dd3602007-09-14 18:46:51 -06001317 dprintk(ioc, printk(MYIOC_s_ERR_FMT
1318 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001319 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001320 }
1321
Moore, Eric65207fe2006-04-21 16:14:35 -06001322 /* initialize workqueue */
1323
Kay Sieversaab0de22008-05-02 06:02:41 +02001324 snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name),
1325 "mptfc_wq_%d", sh->host_no);
Moore, Eric65207fe2006-04-21 16:14:35 -06001326 ioc->fc_rescan_work_q =
Bhaktipriya Shridhar77d4f082016-08-31 00:33:05 +05301327 alloc_ordered_workqueue(ioc->fc_rescan_work_q_name,
1328 WQ_MEM_RECLAIM);
Wei Yongjunc08b3f92016-09-10 16:06:36 +00001329 if (!ioc->fc_rescan_work_q) {
1330 error = -ENOMEM;
Moore, Eric65207fe2006-04-21 16:14:35 -06001331 goto out_mptfc_probe;
Wei Yongjunc08b3f92016-09-10 16:06:36 +00001332 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001333
1334 /*
Michael Reed80d3ac72006-05-24 15:07:09 -05001335 * Pre-fetch FC port WWN and stuff...
1336 * (FCPortPage0_t stuff)
1337 */
1338 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1339 (void) mptfc_GetFcPortPage0(ioc, ii);
1340 }
Michael Reedca2f9382006-05-24 15:07:24 -05001341 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001342
1343 /*
Moore, Eric65207fe2006-04-21 16:14:35 -06001344 * scan for rports -
1345 * by doing it via the workqueue, some locking is eliminated
1346 */
1347
Moore, Eric65207fe2006-04-21 16:14:35 -06001348 queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
1349 flush_workqueue(ioc->fc_rescan_work_q);
Michael Reed05e8ec12006-01-13 14:31:54 -06001350
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001351 return 0;
1352
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001353out_mptfc_probe:
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001354
1355 mptscsih_remove(pdev);
1356 return error;
1357}
1358
1359static struct pci_driver mptfc_driver = {
1360 .name = "mptfc",
1361 .id_table = mptfc_pci_table,
1362 .probe = mptfc_probe,
Greg Kroah-Hartman47b1ea72012-12-21 15:04:26 -08001363 .remove = mptfc_remove,
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001364 .shutdown = mptscsih_shutdown,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001365#ifdef CONFIG_PM
1366 .suspend = mptscsih_suspend,
1367 .resume = mptscsih_resume,
1368#endif
1369};
1370
Michael Reed80d3ac72006-05-24 15:07:09 -05001371static int
1372mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1373{
1374 MPT_SCSI_HOST *hd;
1375 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1376 unsigned long flags;
1377 int rc=1;
1378
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05301379 if (ioc->bus_type != FC)
1380 return 0;
1381
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301382 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Michael Reed80d3ac72006-05-24 15:07:09 -05001383 ioc->name, event));
1384
1385 if (ioc->sh == NULL ||
Eric Mooree7eae9f2007-09-29 10:15:59 -06001386 ((hd = shost_priv(ioc->sh)) == NULL))
Michael Reed80d3ac72006-05-24 15:07:09 -05001387 return 1;
1388
1389 switch (event) {
1390 case MPI_EVENT_RESCAN:
1391 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1392 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001393 queue_work(ioc->fc_rescan_work_q,
1394 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001395 }
1396 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1397 break;
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +05301398 case MPI_EVENT_LINK_STATUS_CHANGE:
1399 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1400 if (ioc->fc_rescan_work_q) {
1401 queue_work(ioc->fc_rescan_work_q,
1402 &ioc->fc_lsc_work);
1403 }
1404 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1405 break;
Michael Reed80d3ac72006-05-24 15:07:09 -05001406 default:
1407 rc = mptscsih_event_process(ioc,pEvReply);
1408 break;
1409 }
1410 return rc;
1411}
1412
1413static int
1414mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1415{
1416 int rc;
1417 unsigned long flags;
1418
1419 rc = mptscsih_ioc_reset(ioc,reset_phase);
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05301420 if ((ioc->bus_type != FC) || (!rc))
Michael Reed80d3ac72006-05-24 15:07:09 -05001421 return rc;
1422
1423
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301424 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1425 ": IOC %s_reset routed to FC host driver!\n",ioc->name,
Michael Reed80d3ac72006-05-24 15:07:09 -05001426 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
1427 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
1428
1429 if (reset_phase == MPT_IOC_SETUP_RESET) {
Michael Reed419835e2006-05-24 15:07:40 -05001430 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1431 if (ioc->fc_rescan_work_q) {
1432 queue_work(ioc->fc_rescan_work_q,
1433 &ioc->fc_setup_reset_work);
1434 }
1435 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
Michael Reed80d3ac72006-05-24 15:07:09 -05001436 }
1437
1438 else if (reset_phase == MPT_IOC_PRE_RESET) {
1439 }
1440
1441 else { /* MPT_IOC_POST_RESET */
Michael Reedca2f9382006-05-24 15:07:24 -05001442 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001443 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1444 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001445 queue_work(ioc->fc_rescan_work_q,
1446 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001447 }
1448 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1449 }
1450 return 1;
1451}
1452
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001453/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1454/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001455 * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001456 *
1457 * Returns 0 for success, non-zero for failure.
1458 */
1459static int __init
1460mptfc_init(void)
1461{
Michael Reed05e8ec12006-01-13 14:31:54 -06001462 int error;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001463
1464 show_mptmod_ver(my_NAME, my_VERSION);
1465
Michael Reedca2f9382006-05-24 15:07:24 -05001466 /* sanity check module parameters */
1467 if (mptfc_dev_loss_tmo <= 0)
Michael Reed05e8ec12006-01-13 14:31:54 -06001468 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
1469
1470 mptfc_transport_template =
1471 fc_attach_transport(&mptfc_transport_functions);
1472
1473 if (!mptfc_transport_template)
1474 return -ENODEV;
1475
Kashyap, Desai213aaca2010-07-26 18:57:36 +05301476 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER,
1477 "mptscsih_scandv_complete");
1478 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER,
1479 "mptscsih_scandv_complete");
1480 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER,
1481 "mptscsih_scandv_complete");
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001482
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301483 mpt_event_register(mptfcDoneCtx, mptfc_event_process);
1484 mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001485
Michael Reed05e8ec12006-01-13 14:31:54 -06001486 error = pci_register_driver(&mptfc_driver);
Michael Reed3bc7bf12006-01-25 18:05:18 -07001487 if (error)
Michael Reed05e8ec12006-01-13 14:31:54 -06001488 fc_release_transport(mptfc_transport_template);
Michael Reed05e8ec12006-01-13 14:31:54 -06001489
1490 return error;
1491}
1492
1493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1494/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001495 * mptfc_remove - Remove fc infrastructure for devices
Michael Reed05e8ec12006-01-13 14:31:54 -06001496 * @pdev: Pointer to pci_dev structure
1497 *
1498 */
Greg Kroah-Hartman47b1ea72012-12-21 15:04:26 -08001499static void mptfc_remove(struct pci_dev *pdev)
Michael Reed05e8ec12006-01-13 14:31:54 -06001500{
Moore, Eric65207fe2006-04-21 16:14:35 -06001501 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1502 struct mptfc_rport_info *p, *n;
1503 struct workqueue_struct *work_q;
1504 unsigned long flags;
Michael Reedca2f9382006-05-24 15:07:24 -05001505 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001506
1507 /* destroy workqueue */
1508 if ((work_q=ioc->fc_rescan_work_q)) {
1509 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1510 ioc->fc_rescan_work_q = NULL;
1511 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1512 destroy_workqueue(work_q);
1513 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001514
1515 fc_remove_host(ioc->sh);
1516
1517 list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
1518 list_del(&p->list);
1519 kfree(p);
1520 }
1521
Michael Reedca2f9382006-05-24 15:07:24 -05001522 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
1523 if (ioc->fc_data.fc_port_page1[ii].data) {
1524 pci_free_consistent(ioc->pcidev,
1525 ioc->fc_data.fc_port_page1[ii].pg_sz,
1526 (u8 *) ioc->fc_data.fc_port_page1[ii].data,
1527 ioc->fc_data.fc_port_page1[ii].dma);
1528 ioc->fc_data.fc_port_page1[ii].data = NULL;
1529 }
1530 }
1531
Michael Reed05e8ec12006-01-13 14:31:54 -06001532 mptscsih_remove(pdev);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001533}
1534
1535/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1537/**
1538 * mptfc_exit - Unregisters MPT adapter(s)
1539 *
1540 */
1541static void __exit
1542mptfc_exit(void)
1543{
1544 pci_unregister_driver(&mptfc_driver);
Michael Reed05e8ec12006-01-13 14:31:54 -06001545 fc_release_transport(mptfc_transport_template);
1546
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001547 mpt_reset_deregister(mptfcDoneCtx);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001548 mpt_event_deregister(mptfcDoneCtx);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001549
1550 mpt_deregister(mptfcInternalCtx);
1551 mpt_deregister(mptfcTaskCtx);
1552 mpt_deregister(mptfcDoneCtx);
1553}
1554
1555module_init(mptfc_init);
1556module_exit(mptfc_exit);