blob: 612ab3c51a6b7c9e31ff2eaacd460fa87e09a916 [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>
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040057
58#include <scsi/scsi.h>
59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_device.h>
61#include <scsi/scsi_host.h>
62#include <scsi/scsi_tcq.h>
Michael Reed05e8ec12006-01-13 14:31:54 -060063#include <scsi/scsi_transport_fc.h>
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040064
65#include "mptbase.h"
66#include "mptscsih.h"
67
68/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
69#define my_NAME "Fusion MPT FC Host driver"
70#define my_VERSION MPT_LINUX_VERSION_COMMON
71#define MYNAM "mptfc"
72
73MODULE_AUTHOR(MODULEAUTHOR);
74MODULE_DESCRIPTION(my_NAME);
75MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070076MODULE_VERSION(my_VERSION);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040077
78/* Command line args */
Michael Reed05e8ec12006-01-13 14:31:54 -060079#define MPTFC_DEV_LOSS_TMO (60)
80static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO; /* reasonable default */
81module_param(mptfc_dev_loss_tmo, int, 0);
82MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "
83 " transport to wait for an rport to "
84 " return following a device loss event."
85 " Default=60.");
86
Eric Moore793955f2007-01-29 09:42:20 -070087/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
88#define MPTFC_MAX_LUN (16895)
89static int max_lun = MPTFC_MAX_LUN;
90module_param(max_lun, int, 0);
91MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
92
Prakash, Sathyaf606f572007-08-14 16:12:53 +053093static u8 mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040096
Michael Reed3bc7bf12006-01-25 18:05:18 -070097static int mptfc_target_alloc(struct scsi_target *starget);
98static int mptfc_slave_alloc(struct scsi_device *sdev);
Michael Reed05e8ec12006-01-13 14:31:54 -060099static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700100 void (*done)(struct scsi_cmnd *));
101static 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);
103static void __devexit 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",
112 .proc_info = mptscsih_proc_info,
113 .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
Michael Reed35508e42006-10-06 15:39:25 -0500207 "mptfc_block_error_handler.%d: %d:%d, 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
Michael Reed35508e42006-10-06 15:39:25 -0500221 "%s.%d: %d:%d, 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
Michael Reed35508e42006-10-06 15:39:25 -0500229 "%s.%d: %d:%d, 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;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700484 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600485 }
Moore, Eric65207fe2006-04-21 16:14:35 -0600486 *((struct mptfc_rport_info **)rport->dd_data) = ri;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500487 /* scan will be scheduled once rport becomes a target */
488 fc_remote_port_rolechg(rport,roles);
Moore, Eric65207fe2006-04-21 16:14:35 -0600489
490 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
491 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530492 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed3bc7bf12006-01-25 18:05:18 -0700493 "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600494 "rport tid %d, tmo %d\n",
Michael Reed3bc7bf12006-01-25 18:05:18 -0700495 ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700496 ioc->sh->host_no,
Michael Reed05e8ec12006-01-13 14:31:54 -0600497 pg0->PortIdentifier,
Moore, Eric65207fe2006-04-21 16:14:35 -0600498 (unsigned long long)nn,
499 (unsigned long long)pn,
Michael Reed05e8ec12006-01-13 14:31:54 -0600500 pg0->CurrentTargetID,
501 ri->rport->scsi_target_id,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700502 ri->rport->dev_loss_tmo));
Michael Reed05e8ec12006-01-13 14:31:54 -0600503 } else {
504 list_del(&ri->list);
505 kfree(ri);
506 ri = NULL;
507 }
508 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600509}
510
511/*
Michael Reed3bc7bf12006-01-25 18:05:18 -0700512 * OS entry point to allow for host driver to free allocated memory
513 * Called if no device present or device being unloaded
514 */
515static void
516mptfc_target_destroy(struct scsi_target *starget)
517{
518 struct fc_rport *rport;
519 struct mptfc_rport_info *ri;
520
521 rport = starget_to_rport(starget);
522 if (rport) {
523 ri = *((struct mptfc_rport_info **)rport->dd_data);
524 if (ri) /* better be! */
525 ri->starget = NULL;
526 }
527 if (starget->hostdata)
528 kfree(starget->hostdata);
529 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
651mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
652{
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;
Michael Reed05e8ec12006-01-13 14:31:54 -0600660 done(SCpnt);
661 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;
Michael Reed35508e42006-10-06 15:39:25 -0500667 done(SCpnt);
668 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;
675 done(SCpnt);
676 return 0;
677 }
678
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530679 return mptscsih_qcmd(SCpnt,done);
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;
1094
1095 /* reset about to happen, delete (block) all rports */
1096 list_for_each_entry(ri, &ioc->fc_rports, list) {
1097 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1098 ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
1099 fc_remote_port_delete(ri->rport); /* won't sleep */
1100 ri->rport = NULL;
1101
1102 pn = (u64)ri->pg0.WWPN.High << 32 |
1103 (u64)ri->pg0.WWPN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301104 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed419835e2006-05-24 15:07:40 -05001105 "mptfc_setup_reset.%d: %llx deleted\n",
1106 ioc->name,
1107 ioc->sh->host_no,
1108 (unsigned long long)pn));
1109 }
1110 }
1111}
1112
1113static void
David Howellsc4028952006-11-22 14:57:56 +00001114mptfc_rescan_devices(struct work_struct *work)
Michael Reed05e8ec12006-01-13 14:31:54 -06001115{
David Howellsc4028952006-11-22 14:57:56 +00001116 MPT_ADAPTER *ioc =
1117 container_of(work, MPT_ADAPTER, fc_rescan_work);
Michael Reed05e8ec12006-01-13 14:31:54 -06001118 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001119 u64 pn;
Michael Reed05e8ec12006-01-13 14:31:54 -06001120 struct mptfc_rport_info *ri;
1121
Michael Reed3a0c56d2006-07-31 12:19:50 -05001122 /* start by tagging all ports as missing */
1123 list_for_each_entry(ri, &ioc->fc_rports, list) {
1124 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1125 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
Michael Reed05e8ec12006-01-13 14:31:54 -06001126 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001127 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001128
Michael Reed3a0c56d2006-07-31 12:19:50 -05001129 /*
1130 * now rescan devices known to adapter,
1131 * will reregister existing rports
1132 */
1133 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1134 (void) mptfc_GetFcPortPage0(ioc, ii);
1135 mptfc_init_host_attr(ioc, ii); /* refresh */
1136 mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev);
1137 }
1138
1139 /* delete devices still missing */
1140 list_for_each_entry(ri, &ioc->fc_rports, list) {
1141 /* if newly missing, delete it */
1142 if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
1143
1144 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
1145 MPT_RPORT_INFO_FLAGS_MISSING);
1146 fc_remote_port_delete(ri->rport); /* won't sleep */
1147 ri->rport = NULL;
1148
1149 pn = (u64)ri->pg0.WWPN.High << 32 |
1150 (u64)ri->pg0.WWPN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301151 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed3a0c56d2006-07-31 12:19:50 -05001152 "mptfc_rescan.%d: %llx deleted\n",
1153 ioc->name,
1154 ioc->sh->host_no,
1155 (unsigned long long)pn));
Michael Reed05e8ec12006-01-13 14:31:54 -06001156 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001157 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001158}
1159
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001160static int
1161mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1162{
1163 struct Scsi_Host *sh;
1164 MPT_SCSI_HOST *hd;
1165 MPT_ADAPTER *ioc;
1166 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001167 int ii;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001168 int numSGE = 0;
1169 int scale;
1170 int ioc_cap;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001171 int error=0;
1172 int r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001173
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001174 if ((r = mpt_attach(pdev,id)) != 0)
1175 return r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001176
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001177 ioc = pci_get_drvdata(pdev);
Moore, Eric Dean d335cc32005-04-30 17:09:38 -05001178 ioc->DoneCtx = mptfcDoneCtx;
1179 ioc->TaskCtx = mptfcTaskCtx;
1180 ioc->InternalCtx = mptfcInternalCtx;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001181
1182 /* Added sanity check on readiness of the MPT adapter.
1183 */
1184 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1185 printk(MYIOC_s_WARN_FMT
1186 "Skipping because it's not operational!\n",
1187 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001188 error = -ENODEV;
1189 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001190 }
1191
1192 if (!ioc->active) {
1193 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1194 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001195 error = -ENODEV;
1196 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001197 }
1198
1199 /* Sanity check - ensure at least 1 port is INITIATOR capable
1200 */
1201 ioc_cap = 0;
1202 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1203 if (ioc->pfacts[ii].ProtocolFlags &
1204 MPI_PORTFACTS_PROTOCOL_INITIATOR)
1205 ioc_cap ++;
1206 }
1207
1208 if (!ioc_cap) {
1209 printk(MYIOC_s_WARN_FMT
1210 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1211 ioc->name, ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001212 return 0;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001213 }
1214
1215 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
1216
1217 if (!sh) {
1218 printk(MYIOC_s_WARN_FMT
1219 "Unable to register controller with SCSI subsystem\n",
1220 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001221 error = -1;
1222 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001223 }
1224
Michael Reed80d3ac72006-05-24 15:07:09 -05001225 spin_lock_init(&ioc->fc_rescan_work_lock);
David Howellsc4028952006-11-22 14:57:56 +00001226 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
1227 INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +05301228 INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change);
Michael Reed05e8ec12006-01-13 14:31:54 -06001229
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001230 spin_lock_irqsave(&ioc->FreeQlock, flags);
1231
1232 /* Attach the SCSI Host to the IOC structure
1233 */
1234 ioc->sh = sh;
1235
1236 sh->io_port = 0;
1237 sh->n_io_port = 0;
1238 sh->irq = 0;
1239
1240 /* set 16 byte cdb's */
1241 sh->max_cmd_len = 16;
1242
Eric Moore793955f2007-01-29 09:42:20 -07001243 sh->max_id = ioc->pfacts->MaxDevices;
1244 sh->max_lun = max_lun;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001245
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001246 /* Required entry.
1247 */
1248 sh->unique_id = ioc->id;
1249
1250 /* Verify that we won't exceed the maximum
1251 * number of chain buffers
1252 * We can optimize: ZZ = req_sz/sizeof(SGE)
1253 * For 32bit SGE's:
1254 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1255 * + (req_sz - 64)/sizeof(SGE)
1256 * A slightly different algorithm is required for
1257 * 64bit SGEs.
1258 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301259 scale = ioc->req_sz/ioc->SGE_size;
1260 if (ioc->sg_addr_size == sizeof(u64)) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001261 numSGE = (scale - 1) *
1262 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301263 (ioc->req_sz - 60) / ioc->SGE_size;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001264 } else {
1265 numSGE = 1 + (scale - 1) *
1266 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301267 (ioc->req_sz - 64) / ioc->SGE_size;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001268 }
1269
1270 if (numSGE < sh->sg_tablesize) {
1271 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301272 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001273 "Resetting sg_tablesize to %d from %d\n",
1274 ioc->name, numSGE, sh->sg_tablesize));
1275 sh->sg_tablesize = numSGE;
1276 }
1277
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001278 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1279
Eric Mooree7eae9f2007-09-29 10:15:59 -06001280 hd = shost_priv(sh);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001281 hd->ioc = ioc;
1282
1283 /* SCSI needs scsi_cmnd lookup table!
1284 * (with size equal to req_depth*PtrSz!)
1285 */
Eric Mooree8206382007-09-29 10:16:53 -06001286 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
1287 if (!ioc->ScsiLookup) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001288 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001289 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001290 }
Eric Mooree8206382007-09-29 10:16:53 -06001291 spin_lock_init(&ioc->scsi_lookup_lock);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001292
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301293 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06001294 ioc->name, ioc->ScsiLookup));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001295
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001296 hd->last_queue_full = 0;
1297
Michael Reed05e8ec12006-01-13 14:31:54 -06001298 sh->transportt = mptfc_transport_template;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001299 error = scsi_add_host (sh, &ioc->pcidev->dev);
1300 if(error) {
Eric Moore29dd3602007-09-14 18:46:51 -06001301 dprintk(ioc, printk(MYIOC_s_ERR_FMT
1302 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001303 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001304 }
1305
Moore, Eric65207fe2006-04-21 16:14:35 -06001306 /* initialize workqueue */
1307
Kay Sieversaab0de22008-05-02 06:02:41 +02001308 snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name),
1309 "mptfc_wq_%d", sh->host_no);
Moore, Eric65207fe2006-04-21 16:14:35 -06001310 ioc->fc_rescan_work_q =
1311 create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
1312 if (!ioc->fc_rescan_work_q)
1313 goto out_mptfc_probe;
1314
1315 /*
Michael Reed80d3ac72006-05-24 15:07:09 -05001316 * Pre-fetch FC port WWN and stuff...
1317 * (FCPortPage0_t stuff)
1318 */
1319 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1320 (void) mptfc_GetFcPortPage0(ioc, ii);
1321 }
Michael Reedca2f9382006-05-24 15:07:24 -05001322 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001323
1324 /*
Moore, Eric65207fe2006-04-21 16:14:35 -06001325 * scan for rports -
1326 * by doing it via the workqueue, some locking is eliminated
1327 */
1328
Moore, Eric65207fe2006-04-21 16:14:35 -06001329 queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
1330 flush_workqueue(ioc->fc_rescan_work_q);
Michael Reed05e8ec12006-01-13 14:31:54 -06001331
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001332 return 0;
1333
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001334out_mptfc_probe:
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001335
1336 mptscsih_remove(pdev);
1337 return error;
1338}
1339
1340static struct pci_driver mptfc_driver = {
1341 .name = "mptfc",
1342 .id_table = mptfc_pci_table,
1343 .probe = mptfc_probe,
Michael Reed05e8ec12006-01-13 14:31:54 -06001344 .remove = __devexit_p(mptfc_remove),
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001345 .shutdown = mptscsih_shutdown,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001346#ifdef CONFIG_PM
1347 .suspend = mptscsih_suspend,
1348 .resume = mptscsih_resume,
1349#endif
1350};
1351
Michael Reed80d3ac72006-05-24 15:07:09 -05001352static int
1353mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1354{
1355 MPT_SCSI_HOST *hd;
1356 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1357 unsigned long flags;
1358 int rc=1;
1359
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301360 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Michael Reed80d3ac72006-05-24 15:07:09 -05001361 ioc->name, event));
1362
1363 if (ioc->sh == NULL ||
Eric Mooree7eae9f2007-09-29 10:15:59 -06001364 ((hd = shost_priv(ioc->sh)) == NULL))
Michael Reed80d3ac72006-05-24 15:07:09 -05001365 return 1;
1366
1367 switch (event) {
1368 case MPI_EVENT_RESCAN:
1369 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1370 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001371 queue_work(ioc->fc_rescan_work_q,
1372 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001373 }
1374 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1375 break;
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +05301376 case MPI_EVENT_LINK_STATUS_CHANGE:
1377 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1378 if (ioc->fc_rescan_work_q) {
1379 queue_work(ioc->fc_rescan_work_q,
1380 &ioc->fc_lsc_work);
1381 }
1382 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1383 break;
Michael Reed80d3ac72006-05-24 15:07:09 -05001384 default:
1385 rc = mptscsih_event_process(ioc,pEvReply);
1386 break;
1387 }
1388 return rc;
1389}
1390
1391static int
1392mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1393{
1394 int rc;
1395 unsigned long flags;
1396
1397 rc = mptscsih_ioc_reset(ioc,reset_phase);
1398 if (rc == 0)
1399 return rc;
1400
1401
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301402 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1403 ": IOC %s_reset routed to FC host driver!\n",ioc->name,
Michael Reed80d3ac72006-05-24 15:07:09 -05001404 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
1405 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
1406
1407 if (reset_phase == MPT_IOC_SETUP_RESET) {
Michael Reed419835e2006-05-24 15:07:40 -05001408 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1409 if (ioc->fc_rescan_work_q) {
1410 queue_work(ioc->fc_rescan_work_q,
1411 &ioc->fc_setup_reset_work);
1412 }
1413 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
Michael Reed80d3ac72006-05-24 15:07:09 -05001414 }
1415
1416 else if (reset_phase == MPT_IOC_PRE_RESET) {
1417 }
1418
1419 else { /* MPT_IOC_POST_RESET */
Michael Reedca2f9382006-05-24 15:07:24 -05001420 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001421 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1422 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001423 queue_work(ioc->fc_rescan_work_q,
1424 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001425 }
1426 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1427 }
1428 return 1;
1429}
1430
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1432/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001433 * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001434 *
1435 * Returns 0 for success, non-zero for failure.
1436 */
1437static int __init
1438mptfc_init(void)
1439{
Michael Reed05e8ec12006-01-13 14:31:54 -06001440 int error;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001441
1442 show_mptmod_ver(my_NAME, my_VERSION);
1443
Michael Reedca2f9382006-05-24 15:07:24 -05001444 /* sanity check module parameters */
1445 if (mptfc_dev_loss_tmo <= 0)
Michael Reed05e8ec12006-01-13 14:31:54 -06001446 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
1447
1448 mptfc_transport_template =
1449 fc_attach_transport(&mptfc_transport_functions);
1450
1451 if (!mptfc_transport_template)
1452 return -ENODEV;
1453
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001454 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
1455 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
1456 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
1457
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301458 mpt_event_register(mptfcDoneCtx, mptfc_event_process);
1459 mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001460
Michael Reed05e8ec12006-01-13 14:31:54 -06001461 error = pci_register_driver(&mptfc_driver);
Michael Reed3bc7bf12006-01-25 18:05:18 -07001462 if (error)
Michael Reed05e8ec12006-01-13 14:31:54 -06001463 fc_release_transport(mptfc_transport_template);
Michael Reed05e8ec12006-01-13 14:31:54 -06001464
1465 return error;
1466}
1467
1468/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1469/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001470 * mptfc_remove - Remove fc infrastructure for devices
Michael Reed05e8ec12006-01-13 14:31:54 -06001471 * @pdev: Pointer to pci_dev structure
1472 *
1473 */
Michael Reed3bc7bf12006-01-25 18:05:18 -07001474static void __devexit
1475mptfc_remove(struct pci_dev *pdev)
Michael Reed05e8ec12006-01-13 14:31:54 -06001476{
Moore, Eric65207fe2006-04-21 16:14:35 -06001477 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1478 struct mptfc_rport_info *p, *n;
1479 struct workqueue_struct *work_q;
1480 unsigned long flags;
Michael Reedca2f9382006-05-24 15:07:24 -05001481 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001482
1483 /* destroy workqueue */
1484 if ((work_q=ioc->fc_rescan_work_q)) {
1485 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1486 ioc->fc_rescan_work_q = NULL;
1487 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1488 destroy_workqueue(work_q);
1489 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001490
1491 fc_remove_host(ioc->sh);
1492
1493 list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
1494 list_del(&p->list);
1495 kfree(p);
1496 }
1497
Michael Reedca2f9382006-05-24 15:07:24 -05001498 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
1499 if (ioc->fc_data.fc_port_page1[ii].data) {
1500 pci_free_consistent(ioc->pcidev,
1501 ioc->fc_data.fc_port_page1[ii].pg_sz,
1502 (u8 *) ioc->fc_data.fc_port_page1[ii].data,
1503 ioc->fc_data.fc_port_page1[ii].dma);
1504 ioc->fc_data.fc_port_page1[ii].data = NULL;
1505 }
1506 }
1507
Michael Reed05e8ec12006-01-13 14:31:54 -06001508 mptscsih_remove(pdev);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001509}
1510
1511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1512/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1513/**
1514 * mptfc_exit - Unregisters MPT adapter(s)
1515 *
1516 */
1517static void __exit
1518mptfc_exit(void)
1519{
1520 pci_unregister_driver(&mptfc_driver);
Michael Reed05e8ec12006-01-13 14:31:54 -06001521 fc_release_transport(mptfc_transport_template);
1522
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001523 mpt_reset_deregister(mptfcDoneCtx);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001524 mpt_event_deregister(mptfcDoneCtx);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001525
1526 mpt_deregister(mptfcInternalCtx);
1527 mpt_deregister(mptfcTaskCtx);
1528 mpt_deregister(mptfcDoneCtx);
1529}
1530
1531module_init(mptfc_init);
1532module_exit(mptfc_exit);