blob: b36cae9ec6db6c81041f8dccd8b3ce59db466f2e [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 Reed35508e42006-10-06 15:39:25 -0500198
Eric Mooree7eae9f2007-09-29 10:15:59 -0600199 hd = shost_priv(SCpnt->device->host);
Eric Mooree80b0022007-09-14 18:49:03 -0600200 ioc = hd->ioc;
Michael Reed35508e42006-10-06 15:39:25 -0500201 spin_lock_irqsave(shost->host_lock, flags);
202 while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
203 spin_unlock_irqrestore(shost->host_lock, flags);
Eric Mooree80b0022007-09-14 18:49:03 -0600204 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed35508e42006-10-06 15:39:25 -0500205 "mptfc_block_error_handler.%d: %d:%d, port status is "
206 "DID_IMM_RETRY, deferring %s recovery.\n",
Eric Mooree7eae9f2007-09-29 10:15:59 -0600207 ioc->name, ioc->sh->host_no,
Eric Moore29dd3602007-09-14 18:46:51 -0600208 SCpnt->device->id, SCpnt->device->lun, caller));
Michael Reed35508e42006-10-06 15:39:25 -0500209 msleep(1000);
210 spin_lock_irqsave(shost->host_lock, flags);
211 }
212 spin_unlock_irqrestore(shost->host_lock, flags);
213
214 if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
Eric Mooree80b0022007-09-14 18:49:03 -0600215 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed35508e42006-10-06 15:39:25 -0500216 "%s.%d: %d:%d, failing recovery, "
Eric Moorea69de502007-09-14 18:48:19 -0600217 "port state %d, vdevice %p.\n", caller,
Eric Mooree7eae9f2007-09-29 10:15:59 -0600218 ioc->name, ioc->sh->host_no,
Eric Moore29dd3602007-09-14 18:46:51 -0600219 SCpnt->device->id, SCpnt->device->lun, ready,
Michael Reed35508e42006-10-06 15:39:25 -0500220 SCpnt->device->hostdata));
221 return FAILED;
222 }
Eric Mooree80b0022007-09-14 18:49:03 -0600223 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed35508e42006-10-06 15:39:25 -0500224 "%s.%d: %d:%d, executing recovery.\n", caller,
Eric Mooree7eae9f2007-09-29 10:15:59 -0600225 ioc->name, ioc->sh->host_no,
Eric Moore29dd3602007-09-14 18:46:51 -0600226 SCpnt->device->id, SCpnt->device->lun));
Michael Reed35508e42006-10-06 15:39:25 -0500227 return (*func)(SCpnt);
228}
229
230static int
231mptfc_abort(struct scsi_cmnd *SCpnt)
232{
233 return
234 mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
235}
236
237static int
238mptfc_dev_reset(struct scsi_cmnd *SCpnt)
239{
240 return
241 mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
242}
243
244static int
245mptfc_bus_reset(struct scsi_cmnd *SCpnt)
246{
247 return
248 mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
249}
250
251static int
252mptfc_host_reset(struct scsi_cmnd *SCpnt)
253{
254 return
255 mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
256}
257
Michael Reed05e8ec12006-01-13 14:31:54 -0600258static void
259mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
260{
261 if (timeout > 0)
262 rport->dev_loss_tmo = timeout;
263 else
264 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
265}
266
267static int
268mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
269{
270 FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
271 FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
272
273 if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
274 if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
275 return 0;
276 if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
277 return -1;
278 return 1;
279 }
280 if ((*aa)->CurrentBus < (*bb)->CurrentBus)
281 return -1;
282 return 1;
283}
284
285static int
286mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
287 void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
288{
289 ConfigPageHeader_t hdr;
290 CONFIGPARMS cfg;
291 FCDevicePage0_t *ppage0_alloc, *fc;
292 dma_addr_t page0_dma;
293 int data_sz;
294 int ii;
295
296 FCDevicePage0_t *p0_array=NULL, *p_p0;
297 FCDevicePage0_t **pp0_array=NULL, **p_pp0;
298
299 int rc = -ENOMEM;
300 U32 port_id = 0xffffff;
301 int num_targ = 0;
302 int max_bus = ioc->facts.MaxBuses;
Eric Moore793955f2007-01-29 09:42:20 -0700303 int max_targ;
Michael Reed05e8ec12006-01-13 14:31:54 -0600304
Eric Moore793955f2007-01-29 09:42:20 -0700305 max_targ = (ioc->facts.MaxDevices == 0) ? 256 : ioc->facts.MaxDevices;
Michael Reed05e8ec12006-01-13 14:31:54 -0600306
307 data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
308 p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL);
309 if (!p0_array)
310 goto out;
311
312 data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
313 p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
314 if (!pp0_array)
315 goto out;
316
317 do {
318 /* Get FC Device Page 0 header */
319 hdr.PageVersion = 0;
320 hdr.PageLength = 0;
321 hdr.PageNumber = 0;
322 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
323 cfg.cfghdr.hdr = &hdr;
324 cfg.physAddr = -1;
325 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
326 cfg.dir = 0;
327 cfg.pageAddr = port_id;
328 cfg.timeout = 0;
329
330 if ((rc = mpt_config(ioc, &cfg)) != 0)
331 break;
332
333 if (hdr.PageLength <= 0)
334 break;
335
336 data_sz = hdr.PageLength * 4;
337 ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
338 &page0_dma);
339 rc = -ENOMEM;
340 if (!ppage0_alloc)
341 break;
342
343 cfg.physAddr = page0_dma;
344 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
345
346 if ((rc = mpt_config(ioc, &cfg)) == 0) {
347 ppage0_alloc->PortIdentifier =
348 le32_to_cpu(ppage0_alloc->PortIdentifier);
349
350 ppage0_alloc->WWNN.Low =
351 le32_to_cpu(ppage0_alloc->WWNN.Low);
352
353 ppage0_alloc->WWNN.High =
354 le32_to_cpu(ppage0_alloc->WWNN.High);
355
356 ppage0_alloc->WWPN.Low =
357 le32_to_cpu(ppage0_alloc->WWPN.Low);
358
359 ppage0_alloc->WWPN.High =
360 le32_to_cpu(ppage0_alloc->WWPN.High);
361
362 ppage0_alloc->BBCredit =
363 le16_to_cpu(ppage0_alloc->BBCredit);
364
365 ppage0_alloc->MaxRxFrameSize =
366 le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
367
368 port_id = ppage0_alloc->PortIdentifier;
369 num_targ++;
370 *p_p0 = *ppage0_alloc; /* save data */
371 *p_pp0++ = p_p0++; /* save addr */
372 }
373 pci_free_consistent(ioc->pcidev, data_sz,
374 (u8 *) ppage0_alloc, page0_dma);
375 if (rc != 0)
376 break;
377
378 } while (port_id <= 0xff0000);
379
380 if (num_targ) {
381 /* sort array */
382 if (num_targ > 1)
383 sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
384 mptfc_FcDevPage0_cmp_func, NULL);
385 /* call caller's func for each targ */
386 for (ii = 0; ii < num_targ; ii++) {
387 fc = *(pp0_array+ii);
388 func(ioc, ioc_port, fc);
389 }
390 }
391
392 out:
Jesper Juhl8f760782006-06-27 02:55:06 -0700393 kfree(pp0_array);
394 kfree(p0_array);
Michael Reed05e8ec12006-01-13 14:31:54 -0600395 return rc;
396}
397
398static int
399mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
400{
401 /* not currently usable */
402 if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
403 MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
404 return -1;
405
406 if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
407 return -1;
408
409 if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
410 return -1;
411
412 /*
413 * board data structure already normalized to platform endianness
414 * shifted to avoid unaligned access on 64 bit architecture
415 */
416 rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
417 rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
418 rid->port_id = pg0->PortIdentifier;
419 rid->roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600420
421 return 0;
422}
423
424static void
425mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
426{
427 struct fc_rport_identifiers rport_ids;
428 struct fc_rport *rport;
429 struct mptfc_rport_info *ri;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700430 int new_ri = 1;
Moore, Eric65207fe2006-04-21 16:14:35 -0600431 u64 pn, nn;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700432 VirtTarget *vtarget;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500433 u32 roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600434
435 if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
436 return;
437
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500438 roles |= FC_RPORT_ROLE_FCP_TARGET;
439 if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
440 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
441
Michael Reed05e8ec12006-01-13 14:31:54 -0600442 /* scan list looking for a match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600443 list_for_each_entry(ri, &ioc->fc_rports, list) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700444 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
445 if (pn == rport_ids.port_name) { /* match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600446 list_move_tail(&ri->list, &ioc->fc_rports);
Michael Reed3bc7bf12006-01-25 18:05:18 -0700447 new_ri = 0;
Michael Reed05e8ec12006-01-13 14:31:54 -0600448 break;
449 }
450 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700451 if (new_ri) { /* allocate one */
Michael Reed05e8ec12006-01-13 14:31:54 -0600452 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
453 if (!ri)
454 return;
Michael Reed05e8ec12006-01-13 14:31:54 -0600455 list_add_tail(&ri->list, &ioc->fc_rports);
456 }
457
458 ri->pg0 = *pg0; /* add/update pg0 data */
459 ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
460
Michael Reed3bc7bf12006-01-25 18:05:18 -0700461 /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
Michael Reed05e8ec12006-01-13 14:31:54 -0600462 if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
463 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700464 rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
Michael Reed05e8ec12006-01-13 14:31:54 -0600465 if (rport) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700466 ri->rport = rport;
467 if (new_ri) /* may have been reset by user */
468 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
Michael Reed05e8ec12006-01-13 14:31:54 -0600469 /*
470 * if already mapped, remap here. If not mapped,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700471 * target_alloc will allocate vtarget and map,
Eric Moorea69de502007-09-14 18:48:19 -0600472 * slave_alloc will fill in vdevice from vtarget.
Michael Reed05e8ec12006-01-13 14:31:54 -0600473 */
Michael Reed3bc7bf12006-01-25 18:05:18 -0700474 if (ri->starget) {
475 vtarget = ri->starget->hostdata;
476 if (vtarget) {
Eric Moore793955f2007-01-29 09:42:20 -0700477 vtarget->id = pg0->CurrentTargetID;
478 vtarget->channel = pg0->CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700479 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600480 }
Moore, Eric65207fe2006-04-21 16:14:35 -0600481 *((struct mptfc_rport_info **)rport->dd_data) = ri;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500482 /* scan will be scheduled once rport becomes a target */
483 fc_remote_port_rolechg(rport,roles);
Moore, Eric65207fe2006-04-21 16:14:35 -0600484
485 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
486 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530487 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed3bc7bf12006-01-25 18:05:18 -0700488 "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600489 "rport tid %d, tmo %d\n",
Michael Reed3bc7bf12006-01-25 18:05:18 -0700490 ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700491 ioc->sh->host_no,
Michael Reed05e8ec12006-01-13 14:31:54 -0600492 pg0->PortIdentifier,
Moore, Eric65207fe2006-04-21 16:14:35 -0600493 (unsigned long long)nn,
494 (unsigned long long)pn,
Michael Reed05e8ec12006-01-13 14:31:54 -0600495 pg0->CurrentTargetID,
496 ri->rport->scsi_target_id,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700497 ri->rport->dev_loss_tmo));
Michael Reed05e8ec12006-01-13 14:31:54 -0600498 } else {
499 list_del(&ri->list);
500 kfree(ri);
501 ri = NULL;
502 }
503 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600504}
505
506/*
Michael Reed3bc7bf12006-01-25 18:05:18 -0700507 * OS entry point to allow for host driver to free allocated memory
508 * Called if no device present or device being unloaded
509 */
510static void
511mptfc_target_destroy(struct scsi_target *starget)
512{
513 struct fc_rport *rport;
514 struct mptfc_rport_info *ri;
515
516 rport = starget_to_rport(starget);
517 if (rport) {
518 ri = *((struct mptfc_rport_info **)rport->dd_data);
519 if (ri) /* better be! */
520 ri->starget = NULL;
521 }
522 if (starget->hostdata)
523 kfree(starget->hostdata);
524 starget->hostdata = NULL;
525}
526
527/*
528 * OS entry point to allow host driver to alloc memory
529 * for each scsi target. Called once per device the bus scan.
530 * Return non-zero if allocation fails.
531 */
532static int
533mptfc_target_alloc(struct scsi_target *starget)
534{
535 VirtTarget *vtarget;
536 struct fc_rport *rport;
537 struct mptfc_rport_info *ri;
538 int rc;
539
540 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
541 if (!vtarget)
542 return -ENOMEM;
543 starget->hostdata = vtarget;
544
545 rc = -ENODEV;
546 rport = starget_to_rport(starget);
547 if (rport) {
548 ri = *((struct mptfc_rport_info **)rport->dd_data);
549 if (ri) { /* better be! */
Eric Moore793955f2007-01-29 09:42:20 -0700550 vtarget->id = ri->pg0.CurrentTargetID;
551 vtarget->channel = ri->pg0.CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700552 ri->starget = starget;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700553 rc = 0;
554 }
555 }
556 if (rc != 0) {
557 kfree(vtarget);
558 starget->hostdata = NULL;
559 }
560
561 return rc;
562}
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530563/*
564 * mptfc_dump_lun_info
565 * @ioc
566 * @rport
567 * @sdev
568 *
569 */
570static void
571mptfc_dump_lun_info(MPT_ADAPTER *ioc, struct fc_rport *rport, struct scsi_device *sdev,
572 VirtTarget *vtarget)
573{
574 u64 nn, pn;
575 struct mptfc_rport_info *ri;
576
577 ri = *((struct mptfc_rport_info **)rport->dd_data);
578 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
579 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
580 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
581 "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
582 "CurrentTargetID %d, %x %llx %llx\n",
583 ioc->name,
584 sdev->host->host_no,
585 vtarget->num_luns,
586 sdev->id, ri->pg0.CurrentTargetID,
587 ri->pg0.PortIdentifier,
588 (unsigned long long)pn,
589 (unsigned long long)nn));
590}
591
Michael Reed3bc7bf12006-01-25 18:05:18 -0700592
593/*
Michael Reed05e8ec12006-01-13 14:31:54 -0600594 * OS entry point to allow host driver to alloc memory
595 * for each scsi device. Called once per device the bus scan.
596 * Return non-zero if allocation fails.
597 * Init memory once per LUN.
598 */
Adrian Bunk03fbcbc2006-01-25 02:00:52 +0100599static int
Michael Reed05e8ec12006-01-13 14:31:54 -0600600mptfc_slave_alloc(struct scsi_device *sdev)
601{
602 MPT_SCSI_HOST *hd;
603 VirtTarget *vtarget;
Eric Moorea69de502007-09-14 18:48:19 -0600604 VirtDevice *vdevice;
Michael Reed05e8ec12006-01-13 14:31:54 -0600605 struct scsi_target *starget;
606 struct fc_rport *rport;
Eric Mooree80b0022007-09-14 18:49:03 -0600607 MPT_ADAPTER *ioc;
Michael Reed05e8ec12006-01-13 14:31:54 -0600608
Moore, Eric65207fe2006-04-21 16:14:35 -0600609 starget = scsi_target(sdev);
610 rport = starget_to_rport(starget);
Michael Reed05e8ec12006-01-13 14:31:54 -0600611
612 if (!rport || fc_remote_port_chkready(rport))
613 return -ENXIO;
614
Eric Mooree7eae9f2007-09-29 10:15:59 -0600615 hd = shost_priv(sdev->host);
Eric Mooree80b0022007-09-14 18:49:03 -0600616 ioc = hd->ioc;
Michael Reed05e8ec12006-01-13 14:31:54 -0600617
Eric Moorea69de502007-09-14 18:48:19 -0600618 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
619 if (!vdevice) {
Michael Reed05e8ec12006-01-13 14:31:54 -0600620 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -0600621 ioc->name, sizeof(VirtDevice));
Michael Reed05e8ec12006-01-13 14:31:54 -0600622 return -ENOMEM;
623 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600624
Michael Reed05e8ec12006-01-13 14:31:54 -0600625
Eric Moorea69de502007-09-14 18:48:19 -0600626 sdev->hostdata = vdevice;
Michael Reed05e8ec12006-01-13 14:31:54 -0600627 vtarget = starget->hostdata;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700628
Michael Reed05e8ec12006-01-13 14:31:54 -0600629 if (vtarget->num_luns == 0) {
Eric Mooree80b0022007-09-14 18:49:03 -0600630 vtarget->ioc_id = ioc->id;
Eric Mooreba856d32006-07-11 17:34:01 -0600631 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
Michael Reed05e8ec12006-01-13 14:31:54 -0600632 }
633
Eric Moorea69de502007-09-14 18:48:19 -0600634 vdevice->vtarget = vtarget;
635 vdevice->lun = sdev->lun;
Michael Reed05e8ec12006-01-13 14:31:54 -0600636
Michael Reed05e8ec12006-01-13 14:31:54 -0600637 vtarget->num_luns++;
638
Moore, Eric65207fe2006-04-21 16:14:35 -0600639
Eric Mooree80b0022007-09-14 18:49:03 -0600640 mptfc_dump_lun_info(ioc, rport, sdev, vtarget);
Michael Reed05e8ec12006-01-13 14:31:54 -0600641
642 return 0;
643}
644
645static int
646mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
647{
Michael Reed3bc7bf12006-01-25 18:05:18 -0700648 struct mptfc_rport_info *ri;
Michael Reed05e8ec12006-01-13 14:31:54 -0600649 struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
650 int err;
Eric Moorea69de502007-09-14 18:48:19 -0600651 VirtDevice *vdevice = SCpnt->device->hostdata;
Michael Reed05e8ec12006-01-13 14:31:54 -0600652
Eric Moorea69de502007-09-14 18:48:19 -0600653 if (!vdevice || !vdevice->vtarget) {
Eric Moore793955f2007-01-29 09:42:20 -0700654 SCpnt->result = DID_NO_CONNECT << 16;
Michael Reed05e8ec12006-01-13 14:31:54 -0600655 done(SCpnt);
656 return 0;
657 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700658
Eric Moore793955f2007-01-29 09:42:20 -0700659 err = fc_remote_port_chkready(rport);
660 if (unlikely(err)) {
661 SCpnt->result = err;
Michael Reed35508e42006-10-06 15:39:25 -0500662 done(SCpnt);
663 return 0;
664 }
665
Moore, Eric65207fe2006-04-21 16:14:35 -0600666 /* dd_data is null until finished adding target */
667 ri = *((struct mptfc_rport_info **)rport->dd_data);
668 if (unlikely(!ri)) {
Moore, Eric65207fe2006-04-21 16:14:35 -0600669 SCpnt->result = DID_IMM_RETRY << 16;
670 done(SCpnt);
671 return 0;
672 }
673
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530674 return mptscsih_qcmd(SCpnt,done);
Michael Reed05e8ec12006-01-13 14:31:54 -0600675}
676
Michael Reed80d3ac72006-05-24 15:07:09 -0500677/*
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +0530678 * mptfc_display_port_link_speed - displaying link speed
679 * @ioc: Pointer to MPT_ADAPTER structure
680 * @portnum: IOC Port number
681 * @pp0dest: port page0 data payload
682 *
683 */
684static void
685mptfc_display_port_link_speed(MPT_ADAPTER *ioc, int portnum, FCPortPage0_t *pp0dest)
686{
687 u8 old_speed, new_speed, state;
688 char *old, *new;
689
690 if (portnum >= 2)
691 return;
692
693 old_speed = ioc->fc_link_speed[portnum];
694 new_speed = pp0dest->CurrentSpeed;
695 state = pp0dest->PortState;
696
697 if (state != MPI_FCPORTPAGE0_PORTSTATE_OFFLINE &&
698 new_speed != MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN) {
699
700 old = old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
701 old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
702 old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
703 "Unknown";
704 new = new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
705 new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
706 new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
707 "Unknown";
708 if (old_speed == 0)
709 printk(MYIOC_s_NOTE_FMT
710 "FC Link Established, Speed = %s\n",
711 ioc->name, new);
712 else if (old_speed != new_speed)
713 printk(MYIOC_s_WARN_FMT
714 "FC Link Speed Change, Old Speed = %s, New Speed = %s\n",
715 ioc->name, old, new);
716
717 ioc->fc_link_speed[portnum] = new_speed;
718 }
719}
720
721/*
Michael Reed80d3ac72006-05-24 15:07:09 -0500722 * mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
723 * @ioc: Pointer to MPT_ADAPTER structure
724 * @portnum: IOC Port number
725 *
726 * Return: 0 for success
727 * -ENOMEM if no memory available
728 * -EPERM if not allowed due to ISR context
729 * -EAGAIN if no msg frames currently available
730 * -EFAULT for non-successful reply or no reply (timeout)
731 * -EINVAL portnum arg out of range (hardwired to two elements)
732 */
733static int
734mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
735{
736 ConfigPageHeader_t hdr;
737 CONFIGPARMS cfg;
738 FCPortPage0_t *ppage0_alloc;
739 FCPortPage0_t *pp0dest;
740 dma_addr_t page0_dma;
741 int data_sz;
742 int copy_sz;
743 int rc;
744 int count = 400;
745
746 if (portnum > 1)
747 return -EINVAL;
748
749 /* Get FCPort Page 0 header */
750 hdr.PageVersion = 0;
751 hdr.PageLength = 0;
752 hdr.PageNumber = 0;
753 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
754 cfg.cfghdr.hdr = &hdr;
755 cfg.physAddr = -1;
756 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
757 cfg.dir = 0;
758 cfg.pageAddr = portnum;
759 cfg.timeout = 0;
760
761 if ((rc = mpt_config(ioc, &cfg)) != 0)
762 return rc;
763
764 if (hdr.PageLength == 0)
765 return 0;
766
767 data_sz = hdr.PageLength * 4;
768 rc = -ENOMEM;
769 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
770 if (ppage0_alloc) {
771
772 try_again:
773 memset((u8 *)ppage0_alloc, 0, data_sz);
774 cfg.physAddr = page0_dma;
775 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
776
777 if ((rc = mpt_config(ioc, &cfg)) == 0) {
778 /* save the data */
779 pp0dest = &ioc->fc_port_page0[portnum];
780 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
781 memcpy(pp0dest, ppage0_alloc, copy_sz);
782
783 /*
784 * Normalize endianness of structure data,
785 * by byte-swapping all > 1 byte fields!
786 */
787 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
788 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
789 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
790 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
791 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
792 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
793 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
794 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
795 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
796 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
797 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
798 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
799 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
800 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
801 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
802 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
803
804 /*
805 * if still doing discovery,
806 * hang loose a while until finished
807 */
Michael Reed77d88ee2006-07-31 12:19:40 -0500808 if ((pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) ||
809 (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE &&
810 (pp0dest->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK)
811 == MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT)) {
Michael Reed80d3ac72006-05-24 15:07:09 -0500812 if (count-- > 0) {
Michael Reedd6be06c2006-05-24 15:07:57 -0500813 msleep(100);
Michael Reed80d3ac72006-05-24 15:07:09 -0500814 goto try_again;
815 }
816 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
817 " complete.\n",
818 ioc->name);
819 }
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +0530820 mptfc_display_port_link_speed(ioc, portnum, pp0dest);
Michael Reed80d3ac72006-05-24 15:07:09 -0500821 }
822
823 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
824 }
825
826 return rc;
827}
828
Michael Reedca2f9382006-05-24 15:07:24 -0500829static int
830mptfc_WriteFcPortPage1(MPT_ADAPTER *ioc, int portnum)
831{
832 ConfigPageHeader_t hdr;
833 CONFIGPARMS cfg;
834 int rc;
835
836 if (portnum > 1)
837 return -EINVAL;
838
839 if (!(ioc->fc_data.fc_port_page1[portnum].data))
840 return -EINVAL;
841
842 /* get fcport page 1 header */
843 hdr.PageVersion = 0;
844 hdr.PageLength = 0;
845 hdr.PageNumber = 1;
846 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
847 cfg.cfghdr.hdr = &hdr;
848 cfg.physAddr = -1;
849 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
850 cfg.dir = 0;
851 cfg.pageAddr = portnum;
852 cfg.timeout = 0;
853
854 if ((rc = mpt_config(ioc, &cfg)) != 0)
855 return rc;
856
857 if (hdr.PageLength == 0)
858 return -ENODEV;
859
860 if (hdr.PageLength*4 != ioc->fc_data.fc_port_page1[portnum].pg_sz)
861 return -EINVAL;
862
863 cfg.physAddr = ioc->fc_data.fc_port_page1[portnum].dma;
864 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
865 cfg.dir = 1;
866
867 rc = mpt_config(ioc, &cfg);
868
869 return rc;
870}
871
872static int
873mptfc_GetFcPortPage1(MPT_ADAPTER *ioc, int portnum)
874{
875 ConfigPageHeader_t hdr;
876 CONFIGPARMS cfg;
877 FCPortPage1_t *page1_alloc;
878 dma_addr_t page1_dma;
879 int data_sz;
880 int rc;
881
882 if (portnum > 1)
883 return -EINVAL;
884
885 /* get fcport page 1 header */
886 hdr.PageVersion = 0;
887 hdr.PageLength = 0;
888 hdr.PageNumber = 1;
889 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
890 cfg.cfghdr.hdr = &hdr;
891 cfg.physAddr = -1;
892 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
893 cfg.dir = 0;
894 cfg.pageAddr = portnum;
895 cfg.timeout = 0;
896
897 if ((rc = mpt_config(ioc, &cfg)) != 0)
898 return rc;
899
900 if (hdr.PageLength == 0)
901 return -ENODEV;
902
903start_over:
904
905 if (ioc->fc_data.fc_port_page1[portnum].data == NULL) {
906 data_sz = hdr.PageLength * 4;
907 if (data_sz < sizeof(FCPortPage1_t))
908 data_sz = sizeof(FCPortPage1_t);
909
910 page1_alloc = (FCPortPage1_t *) pci_alloc_consistent(ioc->pcidev,
911 data_sz,
912 &page1_dma);
913 if (!page1_alloc)
914 return -ENOMEM;
915 }
916 else {
917 page1_alloc = ioc->fc_data.fc_port_page1[portnum].data;
918 page1_dma = ioc->fc_data.fc_port_page1[portnum].dma;
919 data_sz = ioc->fc_data.fc_port_page1[portnum].pg_sz;
920 if (hdr.PageLength * 4 > data_sz) {
921 ioc->fc_data.fc_port_page1[portnum].data = NULL;
922 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
923 page1_alloc, page1_dma);
924 goto start_over;
925 }
926 }
927
928 memset(page1_alloc,0,data_sz);
929
930 cfg.physAddr = page1_dma;
931 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
932
933 if ((rc = mpt_config(ioc, &cfg)) == 0) {
934 ioc->fc_data.fc_port_page1[portnum].data = page1_alloc;
935 ioc->fc_data.fc_port_page1[portnum].pg_sz = data_sz;
936 ioc->fc_data.fc_port_page1[portnum].dma = page1_dma;
937 }
938 else {
939 ioc->fc_data.fc_port_page1[portnum].data = NULL;
940 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
941 page1_alloc, page1_dma);
942 }
943
944 return rc;
945}
946
947static void
948mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
949{
950 int ii;
951 FCPortPage1_t *pp1;
952
953 #define MPTFC_FW_DEVICE_TIMEOUT (1)
954 #define MPTFC_FW_IO_PEND_TIMEOUT (1)
955 #define ON_FLAGS (MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY)
956 #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)
957
958 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
959 if (mptfc_GetFcPortPage1(ioc, ii) != 0)
960 continue;
961 pp1 = ioc->fc_data.fc_port_page1[ii].data;
962 if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)
963 && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)
964 && ((pp1->Flags & ON_FLAGS) == ON_FLAGS)
965 && ((pp1->Flags & OFF_FLAGS) == 0))
966 continue;
967 pp1->InitiatorDeviceTimeout = MPTFC_FW_DEVICE_TIMEOUT;
968 pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT;
969 pp1->Flags &= ~OFF_FLAGS;
970 pp1->Flags |= ON_FLAGS;
971 mptfc_WriteFcPortPage1(ioc, ii);
972 }
973}
974
975
Michael Reed05e8ec12006-01-13 14:31:54 -0600976static void
977mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
978{
Michael Reed5d947f22006-07-31 12:19:30 -0500979 unsigned class = 0;
980 unsigned cos = 0;
981 unsigned speed;
982 unsigned port_type;
983 unsigned port_state;
984 FCPortPage0_t *pp0;
985 struct Scsi_Host *sh;
986 char *sn;
Michael Reed05e8ec12006-01-13 14:31:54 -0600987
988 /* don't know what to do as only one scsi (fc) host was allocated */
989 if (portnum != 0)
990 return;
991
Michael Reed5d947f22006-07-31 12:19:30 -0500992 pp0 = &ioc->fc_port_page0[portnum];
993 sh = ioc->sh;
994
995 sn = fc_host_symbolic_name(sh);
996 snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",
997 ioc->prod_name,
998 MPT_FW_REV_MAGIC_ID_STRING,
999 ioc->facts.FWVersion.Word);
1000
1001 fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;
1002
1003 fc_host_maxframe_size(sh) = pp0->MaxFrameSize;
1004
1005 fc_host_node_name(sh) =
1006 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
1007
1008 fc_host_port_name(sh) =
1009 (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;
1010
1011 fc_host_port_id(sh) = pp0->PortIdentifier;
1012
1013 class = pp0->SupportedServiceClass;
Michael Reed05e8ec12006-01-13 14:31:54 -06001014 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
1015 cos |= FC_COS_CLASS1;
1016 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
1017 cos |= FC_COS_CLASS2;
1018 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
1019 cos |= FC_COS_CLASS3;
Michael Reed5d947f22006-07-31 12:19:30 -05001020 fc_host_supported_classes(sh) = cos;
Michael Reed05e8ec12006-01-13 14:31:54 -06001021
Michael Reed5d947f22006-07-31 12:19:30 -05001022 if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)
1023 speed = FC_PORTSPEED_1GBIT;
1024 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)
1025 speed = FC_PORTSPEED_2GBIT;
1026 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)
1027 speed = FC_PORTSPEED_4GBIT;
1028 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)
1029 speed = FC_PORTSPEED_10GBIT;
1030 else
1031 speed = FC_PORTSPEED_UNKNOWN;
1032 fc_host_speed(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -06001033
Michael Reed5d947f22006-07-31 12:19:30 -05001034 speed = 0;
1035 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)
1036 speed |= FC_PORTSPEED_1GBIT;
1037 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
1038 speed |= FC_PORTSPEED_2GBIT;
1039 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
1040 speed |= FC_PORTSPEED_4GBIT;
1041 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
1042 speed |= FC_PORTSPEED_10GBIT;
1043 fc_host_supported_speeds(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -06001044
Michael Reed5d947f22006-07-31 12:19:30 -05001045 port_state = FC_PORTSTATE_UNKNOWN;
1046 if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)
1047 port_state = FC_PORTSTATE_ONLINE;
1048 else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)
1049 port_state = FC_PORTSTATE_LINKDOWN;
1050 fc_host_port_state(sh) = port_state;
Michael Reed05e8ec12006-01-13 14:31:54 -06001051
Michael Reed5d947f22006-07-31 12:19:30 -05001052 port_type = FC_PORTTYPE_UNKNOWN;
1053 if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)
1054 port_type = FC_PORTTYPE_PTP;
1055 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)
1056 port_type = FC_PORTTYPE_LPORT;
1057 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)
1058 port_type = FC_PORTTYPE_NLPORT;
1059 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)
1060 port_type = FC_PORTTYPE_NPORT;
1061 fc_host_port_type(sh) = port_type;
Michael Reed05e8ec12006-01-13 14:31:54 -06001062
Michael Reed5d947f22006-07-31 12:19:30 -05001063 fc_host_fabric_name(sh) =
1064 (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?
1065 (u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :
1066 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
1067
Michael Reed05e8ec12006-01-13 14:31:54 -06001068}
1069
1070static void
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +05301071mptfc_link_status_change(struct work_struct *work)
1072{
1073 MPT_ADAPTER *ioc =
1074 container_of(work, MPT_ADAPTER, fc_rescan_work);
1075 int ii;
1076
1077 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++)
1078 (void) mptfc_GetFcPortPage0(ioc, ii);
1079
1080}
1081
1082static void
David Howellsc4028952006-11-22 14:57:56 +00001083mptfc_setup_reset(struct work_struct *work)
Michael Reed419835e2006-05-24 15:07:40 -05001084{
David Howellsc4028952006-11-22 14:57:56 +00001085 MPT_ADAPTER *ioc =
1086 container_of(work, MPT_ADAPTER, fc_setup_reset_work);
Michael Reed419835e2006-05-24 15:07:40 -05001087 u64 pn;
1088 struct mptfc_rport_info *ri;
1089
1090 /* reset about to happen, delete (block) all rports */
1091 list_for_each_entry(ri, &ioc->fc_rports, list) {
1092 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1093 ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
1094 fc_remote_port_delete(ri->rport); /* won't sleep */
1095 ri->rport = NULL;
1096
1097 pn = (u64)ri->pg0.WWPN.High << 32 |
1098 (u64)ri->pg0.WWPN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301099 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed419835e2006-05-24 15:07:40 -05001100 "mptfc_setup_reset.%d: %llx deleted\n",
1101 ioc->name,
1102 ioc->sh->host_no,
1103 (unsigned long long)pn));
1104 }
1105 }
1106}
1107
1108static void
David Howellsc4028952006-11-22 14:57:56 +00001109mptfc_rescan_devices(struct work_struct *work)
Michael Reed05e8ec12006-01-13 14:31:54 -06001110{
David Howellsc4028952006-11-22 14:57:56 +00001111 MPT_ADAPTER *ioc =
1112 container_of(work, MPT_ADAPTER, fc_rescan_work);
Michael Reed05e8ec12006-01-13 14:31:54 -06001113 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001114 u64 pn;
Michael Reed05e8ec12006-01-13 14:31:54 -06001115 struct mptfc_rport_info *ri;
1116
Michael Reed3a0c56d2006-07-31 12:19:50 -05001117 /* start by tagging all ports as missing */
1118 list_for_each_entry(ri, &ioc->fc_rports, list) {
1119 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1120 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
Michael Reed05e8ec12006-01-13 14:31:54 -06001121 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001122 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001123
Michael Reed3a0c56d2006-07-31 12:19:50 -05001124 /*
1125 * now rescan devices known to adapter,
1126 * will reregister existing rports
1127 */
1128 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1129 (void) mptfc_GetFcPortPage0(ioc, ii);
1130 mptfc_init_host_attr(ioc, ii); /* refresh */
1131 mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev);
1132 }
1133
1134 /* delete devices still missing */
1135 list_for_each_entry(ri, &ioc->fc_rports, list) {
1136 /* if newly missing, delete it */
1137 if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
1138
1139 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
1140 MPT_RPORT_INFO_FLAGS_MISSING);
1141 fc_remote_port_delete(ri->rport); /* won't sleep */
1142 ri->rport = NULL;
1143
1144 pn = (u64)ri->pg0.WWPN.High << 32 |
1145 (u64)ri->pg0.WWPN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301146 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed3a0c56d2006-07-31 12:19:50 -05001147 "mptfc_rescan.%d: %llx deleted\n",
1148 ioc->name,
1149 ioc->sh->host_no,
1150 (unsigned long long)pn));
Michael Reed05e8ec12006-01-13 14:31:54 -06001151 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001152 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001153}
1154
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001155static int
1156mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1157{
1158 struct Scsi_Host *sh;
1159 MPT_SCSI_HOST *hd;
1160 MPT_ADAPTER *ioc;
1161 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001162 int ii;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001163 int numSGE = 0;
1164 int scale;
1165 int ioc_cap;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001166 int error=0;
1167 int r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001168
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001169 if ((r = mpt_attach(pdev,id)) != 0)
1170 return r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001171
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001172 ioc = pci_get_drvdata(pdev);
Moore, Eric Dean d335cc32005-04-30 17:09:38 -05001173 ioc->DoneCtx = mptfcDoneCtx;
1174 ioc->TaskCtx = mptfcTaskCtx;
1175 ioc->InternalCtx = mptfcInternalCtx;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001176
1177 /* Added sanity check on readiness of the MPT adapter.
1178 */
1179 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1180 printk(MYIOC_s_WARN_FMT
1181 "Skipping because it's not operational!\n",
1182 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001183 error = -ENODEV;
1184 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001185 }
1186
1187 if (!ioc->active) {
1188 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1189 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001190 error = -ENODEV;
1191 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001192 }
1193
1194 /* Sanity check - ensure at least 1 port is INITIATOR capable
1195 */
1196 ioc_cap = 0;
1197 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1198 if (ioc->pfacts[ii].ProtocolFlags &
1199 MPI_PORTFACTS_PROTOCOL_INITIATOR)
1200 ioc_cap ++;
1201 }
1202
1203 if (!ioc_cap) {
1204 printk(MYIOC_s_WARN_FMT
1205 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1206 ioc->name, ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001207 return 0;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001208 }
1209
1210 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
1211
1212 if (!sh) {
1213 printk(MYIOC_s_WARN_FMT
1214 "Unable to register controller with SCSI subsystem\n",
1215 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001216 error = -1;
1217 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001218 }
1219
Michael Reed80d3ac72006-05-24 15:07:09 -05001220 spin_lock_init(&ioc->fc_rescan_work_lock);
David Howellsc4028952006-11-22 14:57:56 +00001221 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
1222 INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +05301223 INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change);
Michael Reed05e8ec12006-01-13 14:31:54 -06001224
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001225 spin_lock_irqsave(&ioc->FreeQlock, flags);
1226
1227 /* Attach the SCSI Host to the IOC structure
1228 */
1229 ioc->sh = sh;
1230
1231 sh->io_port = 0;
1232 sh->n_io_port = 0;
1233 sh->irq = 0;
1234
1235 /* set 16 byte cdb's */
1236 sh->max_cmd_len = 16;
1237
Eric Moore793955f2007-01-29 09:42:20 -07001238 sh->max_id = ioc->pfacts->MaxDevices;
1239 sh->max_lun = max_lun;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001240
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001241 /* Required entry.
1242 */
1243 sh->unique_id = ioc->id;
1244
1245 /* Verify that we won't exceed the maximum
1246 * number of chain buffers
1247 * We can optimize: ZZ = req_sz/sizeof(SGE)
1248 * For 32bit SGE's:
1249 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1250 * + (req_sz - 64)/sizeof(SGE)
1251 * A slightly different algorithm is required for
1252 * 64bit SGEs.
1253 */
1254 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
1255 if (sizeof(dma_addr_t) == sizeof(u64)) {
1256 numSGE = (scale - 1) *
1257 (ioc->facts.MaxChainDepth-1) + scale +
1258 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
1259 sizeof(u32));
1260 } else {
1261 numSGE = 1 + (scale - 1) *
1262 (ioc->facts.MaxChainDepth-1) + scale +
1263 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
1264 sizeof(u32));
1265 }
1266
1267 if (numSGE < sh->sg_tablesize) {
1268 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301269 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001270 "Resetting sg_tablesize to %d from %d\n",
1271 ioc->name, numSGE, sh->sg_tablesize));
1272 sh->sg_tablesize = numSGE;
1273 }
1274
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001275 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1276
Eric Mooree7eae9f2007-09-29 10:15:59 -06001277 hd = shost_priv(sh);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001278 hd->ioc = ioc;
1279
1280 /* SCSI needs scsi_cmnd lookup table!
1281 * (with size equal to req_depth*PtrSz!)
1282 */
Eric Mooree8206382007-09-29 10:16:53 -06001283 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
1284 if (!ioc->ScsiLookup) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001285 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001286 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001287 }
Eric Mooree8206382007-09-29 10:16:53 -06001288 spin_lock_init(&ioc->scsi_lookup_lock);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001289
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301290 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06001291 ioc->name, ioc->ScsiLookup));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001292
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001293 /* Clear the TM flags
1294 */
1295 hd->tmPending = 0;
1296 hd->tmState = TM_STATE_NONE;
1297 hd->resetPending = 0;
1298 hd->abortSCpnt = NULL;
1299
1300 /* Clear the pointer used to store
1301 * single-threaded commands, i.e., those
1302 * issued during a bus scan, dv and
1303 * configuration pages.
1304 */
1305 hd->cmdPtr = NULL;
1306
1307 /* Initialize this SCSI Hosts' timers
1308 * To use, set the timer expires field
1309 * and add_timer
1310 */
1311 init_timer(&hd->timer);
1312 hd->timer.data = (unsigned long) hd;
1313 hd->timer.function = mptscsih_timer_expired;
1314
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001315 init_waitqueue_head(&hd->scandv_waitq);
1316 hd->scandv_wait_done = 0;
1317 hd->last_queue_full = 0;
1318
Michael Reed05e8ec12006-01-13 14:31:54 -06001319 sh->transportt = mptfc_transport_template;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001320 error = scsi_add_host (sh, &ioc->pcidev->dev);
1321 if(error) {
Eric Moore29dd3602007-09-14 18:46:51 -06001322 dprintk(ioc, printk(MYIOC_s_ERR_FMT
1323 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001324 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001325 }
1326
Moore, Eric65207fe2006-04-21 16:14:35 -06001327 /* initialize workqueue */
1328
Kay Sieversaab0de22008-05-02 06:02:41 +02001329 snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name),
1330 "mptfc_wq_%d", sh->host_no);
Moore, Eric65207fe2006-04-21 16:14:35 -06001331 ioc->fc_rescan_work_q =
1332 create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
1333 if (!ioc->fc_rescan_work_q)
1334 goto out_mptfc_probe;
1335
1336 /*
Michael Reed80d3ac72006-05-24 15:07:09 -05001337 * Pre-fetch FC port WWN and stuff...
1338 * (FCPortPage0_t stuff)
1339 */
1340 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1341 (void) mptfc_GetFcPortPage0(ioc, ii);
1342 }
Michael Reedca2f9382006-05-24 15:07:24 -05001343 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001344
1345 /*
Moore, Eric65207fe2006-04-21 16:14:35 -06001346 * scan for rports -
1347 * by doing it via the workqueue, some locking is eliminated
1348 */
1349
Moore, Eric65207fe2006-04-21 16:14:35 -06001350 queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
1351 flush_workqueue(ioc->fc_rescan_work_q);
Michael Reed05e8ec12006-01-13 14:31:54 -06001352
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001353 return 0;
1354
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001355out_mptfc_probe:
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001356
1357 mptscsih_remove(pdev);
1358 return error;
1359}
1360
1361static struct pci_driver mptfc_driver = {
1362 .name = "mptfc",
1363 .id_table = mptfc_pci_table,
1364 .probe = mptfc_probe,
Michael Reed05e8ec12006-01-13 14:31:54 -06001365 .remove = __devexit_p(mptfc_remove),
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001366 .shutdown = mptscsih_shutdown,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001367#ifdef CONFIG_PM
1368 .suspend = mptscsih_suspend,
1369 .resume = mptscsih_resume,
1370#endif
1371};
1372
Michael Reed80d3ac72006-05-24 15:07:09 -05001373static int
1374mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1375{
1376 MPT_SCSI_HOST *hd;
1377 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1378 unsigned long flags;
1379 int rc=1;
1380
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301381 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Michael Reed80d3ac72006-05-24 15:07:09 -05001382 ioc->name, event));
1383
1384 if (ioc->sh == NULL ||
Eric Mooree7eae9f2007-09-29 10:15:59 -06001385 ((hd = shost_priv(ioc->sh)) == NULL))
Michael Reed80d3ac72006-05-24 15:07:09 -05001386 return 1;
1387
1388 switch (event) {
1389 case MPI_EVENT_RESCAN:
1390 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1391 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001392 queue_work(ioc->fc_rescan_work_q,
1393 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001394 }
1395 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1396 break;
Prakash, Sathyaeb5329f2007-08-14 16:19:32 +05301397 case MPI_EVENT_LINK_STATUS_CHANGE:
1398 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1399 if (ioc->fc_rescan_work_q) {
1400 queue_work(ioc->fc_rescan_work_q,
1401 &ioc->fc_lsc_work);
1402 }
1403 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1404 break;
Michael Reed80d3ac72006-05-24 15:07:09 -05001405 default:
1406 rc = mptscsih_event_process(ioc,pEvReply);
1407 break;
1408 }
1409 return rc;
1410}
1411
1412static int
1413mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1414{
1415 int rc;
1416 unsigned long flags;
1417
1418 rc = mptscsih_ioc_reset(ioc,reset_phase);
1419 if (rc == 0)
1420 return rc;
1421
1422
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301423 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1424 ": IOC %s_reset routed to FC host driver!\n",ioc->name,
Michael Reed80d3ac72006-05-24 15:07:09 -05001425 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
1426 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
1427
1428 if (reset_phase == MPT_IOC_SETUP_RESET) {
Michael Reed419835e2006-05-24 15:07:40 -05001429 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1430 if (ioc->fc_rescan_work_q) {
1431 queue_work(ioc->fc_rescan_work_q,
1432 &ioc->fc_setup_reset_work);
1433 }
1434 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
Michael Reed80d3ac72006-05-24 15:07:09 -05001435 }
1436
1437 else if (reset_phase == MPT_IOC_PRE_RESET) {
1438 }
1439
1440 else { /* MPT_IOC_POST_RESET */
Michael Reedca2f9382006-05-24 15:07:24 -05001441 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001442 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1443 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001444 queue_work(ioc->fc_rescan_work_q,
1445 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001446 }
1447 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1448 }
1449 return 1;
1450}
1451
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001452/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1453/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001454 * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001455 *
1456 * Returns 0 for success, non-zero for failure.
1457 */
1458static int __init
1459mptfc_init(void)
1460{
Michael Reed05e8ec12006-01-13 14:31:54 -06001461 int error;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001462
1463 show_mptmod_ver(my_NAME, my_VERSION);
1464
Michael Reedca2f9382006-05-24 15:07:24 -05001465 /* sanity check module parameters */
1466 if (mptfc_dev_loss_tmo <= 0)
Michael Reed05e8ec12006-01-13 14:31:54 -06001467 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
1468
1469 mptfc_transport_template =
1470 fc_attach_transport(&mptfc_transport_functions);
1471
1472 if (!mptfc_transport_template)
1473 return -ENODEV;
1474
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001475 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
1476 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
1477 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
1478
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301479 mpt_event_register(mptfcDoneCtx, mptfc_event_process);
1480 mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001481
Michael Reed05e8ec12006-01-13 14:31:54 -06001482 error = pci_register_driver(&mptfc_driver);
Michael Reed3bc7bf12006-01-25 18:05:18 -07001483 if (error)
Michael Reed05e8ec12006-01-13 14:31:54 -06001484 fc_release_transport(mptfc_transport_template);
Michael Reed05e8ec12006-01-13 14:31:54 -06001485
1486 return error;
1487}
1488
1489/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1490/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001491 * mptfc_remove - Remove fc infrastructure for devices
Michael Reed05e8ec12006-01-13 14:31:54 -06001492 * @pdev: Pointer to pci_dev structure
1493 *
1494 */
Michael Reed3bc7bf12006-01-25 18:05:18 -07001495static void __devexit
1496mptfc_remove(struct pci_dev *pdev)
Michael Reed05e8ec12006-01-13 14:31:54 -06001497{
Moore, Eric65207fe2006-04-21 16:14:35 -06001498 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1499 struct mptfc_rport_info *p, *n;
1500 struct workqueue_struct *work_q;
1501 unsigned long flags;
Michael Reedca2f9382006-05-24 15:07:24 -05001502 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001503
1504 /* destroy workqueue */
1505 if ((work_q=ioc->fc_rescan_work_q)) {
1506 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1507 ioc->fc_rescan_work_q = NULL;
1508 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1509 destroy_workqueue(work_q);
1510 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001511
1512 fc_remove_host(ioc->sh);
1513
1514 list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
1515 list_del(&p->list);
1516 kfree(p);
1517 }
1518
Michael Reedca2f9382006-05-24 15:07:24 -05001519 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
1520 if (ioc->fc_data.fc_port_page1[ii].data) {
1521 pci_free_consistent(ioc->pcidev,
1522 ioc->fc_data.fc_port_page1[ii].pg_sz,
1523 (u8 *) ioc->fc_data.fc_port_page1[ii].data,
1524 ioc->fc_data.fc_port_page1[ii].dma);
1525 ioc->fc_data.fc_port_page1[ii].data = NULL;
1526 }
1527 }
1528
Michael Reed05e8ec12006-01-13 14:31:54 -06001529 mptscsih_remove(pdev);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001530}
1531
1532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1533/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1534/**
1535 * mptfc_exit - Unregisters MPT adapter(s)
1536 *
1537 */
1538static void __exit
1539mptfc_exit(void)
1540{
1541 pci_unregister_driver(&mptfc_driver);
Michael Reed05e8ec12006-01-13 14:31:54 -06001542 fc_release_transport(mptfc_transport_template);
1543
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001544 mpt_reset_deregister(mptfcDoneCtx);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001545 mpt_event_deregister(mptfcDoneCtx);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001546
1547 mpt_deregister(mptfcInternalCtx);
1548 mpt_deregister(mptfcTaskCtx);
1549 mpt_deregister(mptfcDoneCtx);
1550}
1551
1552module_init(mptfc_init);
1553module_exit(mptfc_exit);