blob: 8422c25e4a3e7f71f8ecc26e95a16b416a5c15ac [file] [log] [blame]
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001/*
2 * linux/drivers/message/fusion/mptfc.c
3 * For use with LSI Logic PCI chip/adapter(s)
4 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Eric Moore9f4203b2007-01-04 20:47:47 -07006 * Copyright (c) 1999-2007 LSI Logic 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
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040093static int mptfcDoneCtx = -1;
94static int mptfcTaskCtx = -1;
95static int mptfcInternalCtx = -1; /* Used only for internal commands */
96
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;
197
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530198 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Michael Reed35508e42006-10-06 15:39:25 -0500199 spin_lock_irqsave(shost->host_lock, flags);
200 while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
201 spin_unlock_irqrestore(shost->host_lock, flags);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530202 dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed35508e42006-10-06 15:39:25 -0500203 "mptfc_block_error_handler.%d: %d:%d, port status is "
204 "DID_IMM_RETRY, deferring %s recovery.\n",
205 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
206 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
207 SCpnt->device->id,SCpnt->device->lun,caller));
208 msleep(1000);
209 spin_lock_irqsave(shost->host_lock, flags);
210 }
211 spin_unlock_irqrestore(shost->host_lock, flags);
212
213 if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530214 dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed35508e42006-10-06 15:39:25 -0500215 "%s.%d: %d:%d, failing recovery, "
216 "port state %d, vdev %p.\n", caller,
217 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
218 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
219 SCpnt->device->id,SCpnt->device->lun,ready,
220 SCpnt->device->hostdata));
221 return FAILED;
222 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530223 dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed35508e42006-10-06 15:39:25 -0500224 "%s.%d: %d:%d, executing recovery.\n", caller,
225 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
226 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
227 SCpnt->device->id,SCpnt->device->lun));
228 return (*func)(SCpnt);
229}
230
231static int
232mptfc_abort(struct scsi_cmnd *SCpnt)
233{
234 return
235 mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
236}
237
238static int
239mptfc_dev_reset(struct scsi_cmnd *SCpnt)
240{
241 return
242 mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
243}
244
245static int
246mptfc_bus_reset(struct scsi_cmnd *SCpnt)
247{
248 return
249 mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
250}
251
252static int
253mptfc_host_reset(struct scsi_cmnd *SCpnt)
254{
255 return
256 mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
257}
258
Michael Reed05e8ec12006-01-13 14:31:54 -0600259static void
260mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
261{
262 if (timeout > 0)
263 rport->dev_loss_tmo = timeout;
264 else
265 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
266}
267
268static int
269mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
270{
271 FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
272 FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
273
274 if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
275 if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
276 return 0;
277 if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
278 return -1;
279 return 1;
280 }
281 if ((*aa)->CurrentBus < (*bb)->CurrentBus)
282 return -1;
283 return 1;
284}
285
286static int
287mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
288 void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
289{
290 ConfigPageHeader_t hdr;
291 CONFIGPARMS cfg;
292 FCDevicePage0_t *ppage0_alloc, *fc;
293 dma_addr_t page0_dma;
294 int data_sz;
295 int ii;
296
297 FCDevicePage0_t *p0_array=NULL, *p_p0;
298 FCDevicePage0_t **pp0_array=NULL, **p_pp0;
299
300 int rc = -ENOMEM;
301 U32 port_id = 0xffffff;
302 int num_targ = 0;
303 int max_bus = ioc->facts.MaxBuses;
Eric Moore793955f2007-01-29 09:42:20 -0700304 int max_targ;
Michael Reed05e8ec12006-01-13 14:31:54 -0600305
Eric Moore793955f2007-01-29 09:42:20 -0700306 max_targ = (ioc->facts.MaxDevices == 0) ? 256 : ioc->facts.MaxDevices;
Michael Reed05e8ec12006-01-13 14:31:54 -0600307
308 data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
309 p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL);
310 if (!p0_array)
311 goto out;
312
313 data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
314 p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
315 if (!pp0_array)
316 goto out;
317
318 do {
319 /* Get FC Device Page 0 header */
320 hdr.PageVersion = 0;
321 hdr.PageLength = 0;
322 hdr.PageNumber = 0;
323 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
324 cfg.cfghdr.hdr = &hdr;
325 cfg.physAddr = -1;
326 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
327 cfg.dir = 0;
328 cfg.pageAddr = port_id;
329 cfg.timeout = 0;
330
331 if ((rc = mpt_config(ioc, &cfg)) != 0)
332 break;
333
334 if (hdr.PageLength <= 0)
335 break;
336
337 data_sz = hdr.PageLength * 4;
338 ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
339 &page0_dma);
340 rc = -ENOMEM;
341 if (!ppage0_alloc)
342 break;
343
344 cfg.physAddr = page0_dma;
345 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
346
347 if ((rc = mpt_config(ioc, &cfg)) == 0) {
348 ppage0_alloc->PortIdentifier =
349 le32_to_cpu(ppage0_alloc->PortIdentifier);
350
351 ppage0_alloc->WWNN.Low =
352 le32_to_cpu(ppage0_alloc->WWNN.Low);
353
354 ppage0_alloc->WWNN.High =
355 le32_to_cpu(ppage0_alloc->WWNN.High);
356
357 ppage0_alloc->WWPN.Low =
358 le32_to_cpu(ppage0_alloc->WWPN.Low);
359
360 ppage0_alloc->WWPN.High =
361 le32_to_cpu(ppage0_alloc->WWPN.High);
362
363 ppage0_alloc->BBCredit =
364 le16_to_cpu(ppage0_alloc->BBCredit);
365
366 ppage0_alloc->MaxRxFrameSize =
367 le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
368
369 port_id = ppage0_alloc->PortIdentifier;
370 num_targ++;
371 *p_p0 = *ppage0_alloc; /* save data */
372 *p_pp0++ = p_p0++; /* save addr */
373 }
374 pci_free_consistent(ioc->pcidev, data_sz,
375 (u8 *) ppage0_alloc, page0_dma);
376 if (rc != 0)
377 break;
378
379 } while (port_id <= 0xff0000);
380
381 if (num_targ) {
382 /* sort array */
383 if (num_targ > 1)
384 sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
385 mptfc_FcDevPage0_cmp_func, NULL);
386 /* call caller's func for each targ */
387 for (ii = 0; ii < num_targ; ii++) {
388 fc = *(pp0_array+ii);
389 func(ioc, ioc_port, fc);
390 }
391 }
392
393 out:
Jesper Juhl8f760782006-06-27 02:55:06 -0700394 kfree(pp0_array);
395 kfree(p0_array);
Michael Reed05e8ec12006-01-13 14:31:54 -0600396 return rc;
397}
398
399static int
400mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
401{
402 /* not currently usable */
403 if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
404 MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
405 return -1;
406
407 if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
408 return -1;
409
410 if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
411 return -1;
412
413 /*
414 * board data structure already normalized to platform endianness
415 * shifted to avoid unaligned access on 64 bit architecture
416 */
417 rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
418 rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
419 rid->port_id = pg0->PortIdentifier;
420 rid->roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600421
422 return 0;
423}
424
425static void
426mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
427{
428 struct fc_rport_identifiers rport_ids;
429 struct fc_rport *rport;
430 struct mptfc_rport_info *ri;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700431 int new_ri = 1;
Moore, Eric65207fe2006-04-21 16:14:35 -0600432 u64 pn, nn;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700433 VirtTarget *vtarget;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500434 u32 roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600435
436 if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
437 return;
438
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500439 roles |= FC_RPORT_ROLE_FCP_TARGET;
440 if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
441 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
442
Michael Reed05e8ec12006-01-13 14:31:54 -0600443 /* scan list looking for a match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600444 list_for_each_entry(ri, &ioc->fc_rports, list) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700445 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
446 if (pn == rport_ids.port_name) { /* match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600447 list_move_tail(&ri->list, &ioc->fc_rports);
Michael Reed3bc7bf12006-01-25 18:05:18 -0700448 new_ri = 0;
Michael Reed05e8ec12006-01-13 14:31:54 -0600449 break;
450 }
451 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700452 if (new_ri) { /* allocate one */
Michael Reed05e8ec12006-01-13 14:31:54 -0600453 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
454 if (!ri)
455 return;
Michael Reed05e8ec12006-01-13 14:31:54 -0600456 list_add_tail(&ri->list, &ioc->fc_rports);
457 }
458
459 ri->pg0 = *pg0; /* add/update pg0 data */
460 ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
461
Michael Reed3bc7bf12006-01-25 18:05:18 -0700462 /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
Michael Reed05e8ec12006-01-13 14:31:54 -0600463 if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
464 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700465 rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
Michael Reed05e8ec12006-01-13 14:31:54 -0600466 if (rport) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700467 ri->rport = rport;
468 if (new_ri) /* may have been reset by user */
469 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
Michael Reed05e8ec12006-01-13 14:31:54 -0600470 /*
471 * if already mapped, remap here. If not mapped,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700472 * target_alloc will allocate vtarget and map,
473 * slave_alloc will fill in vdev from vtarget.
Michael Reed05e8ec12006-01-13 14:31:54 -0600474 */
Michael Reed3bc7bf12006-01-25 18:05:18 -0700475 if (ri->starget) {
476 vtarget = ri->starget->hostdata;
477 if (vtarget) {
Eric Moore793955f2007-01-29 09:42:20 -0700478 vtarget->id = pg0->CurrentTargetID;
479 vtarget->channel = pg0->CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700480 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600481 }
Moore, Eric65207fe2006-04-21 16:14:35 -0600482 *((struct mptfc_rport_info **)rport->dd_data) = ri;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500483 /* scan will be scheduled once rport becomes a target */
484 fc_remote_port_rolechg(rport,roles);
Moore, Eric65207fe2006-04-21 16:14:35 -0600485
486 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
487 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530488 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed3bc7bf12006-01-25 18:05:18 -0700489 "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600490 "rport tid %d, tmo %d\n",
Michael Reed3bc7bf12006-01-25 18:05:18 -0700491 ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700492 ioc->sh->host_no,
Michael Reed05e8ec12006-01-13 14:31:54 -0600493 pg0->PortIdentifier,
Moore, Eric65207fe2006-04-21 16:14:35 -0600494 (unsigned long long)nn,
495 (unsigned long long)pn,
Michael Reed05e8ec12006-01-13 14:31:54 -0600496 pg0->CurrentTargetID,
497 ri->rport->scsi_target_id,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700498 ri->rport->dev_loss_tmo));
Michael Reed05e8ec12006-01-13 14:31:54 -0600499 } else {
500 list_del(&ri->list);
501 kfree(ri);
502 ri = NULL;
503 }
504 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600505}
506
507/*
Michael Reed3bc7bf12006-01-25 18:05:18 -0700508 * OS entry point to allow for host driver to free allocated memory
509 * Called if no device present or device being unloaded
510 */
511static void
512mptfc_target_destroy(struct scsi_target *starget)
513{
514 struct fc_rport *rport;
515 struct mptfc_rport_info *ri;
516
517 rport = starget_to_rport(starget);
518 if (rport) {
519 ri = *((struct mptfc_rport_info **)rport->dd_data);
520 if (ri) /* better be! */
521 ri->starget = NULL;
522 }
523 if (starget->hostdata)
524 kfree(starget->hostdata);
525 starget->hostdata = NULL;
526}
527
528/*
529 * OS entry point to allow host driver to alloc memory
530 * for each scsi target. Called once per device the bus scan.
531 * Return non-zero if allocation fails.
532 */
533static int
534mptfc_target_alloc(struct scsi_target *starget)
535{
536 VirtTarget *vtarget;
537 struct fc_rport *rport;
538 struct mptfc_rport_info *ri;
539 int rc;
540
541 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
542 if (!vtarget)
543 return -ENOMEM;
544 starget->hostdata = vtarget;
545
546 rc = -ENODEV;
547 rport = starget_to_rport(starget);
548 if (rport) {
549 ri = *((struct mptfc_rport_info **)rport->dd_data);
550 if (ri) { /* better be! */
Eric Moore793955f2007-01-29 09:42:20 -0700551 vtarget->id = ri->pg0.CurrentTargetID;
552 vtarget->channel = ri->pg0.CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700553 ri->starget = starget;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700554 rc = 0;
555 }
556 }
557 if (rc != 0) {
558 kfree(vtarget);
559 starget->hostdata = NULL;
560 }
561
562 return rc;
563}
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530564/*
565 * mptfc_dump_lun_info
566 * @ioc
567 * @rport
568 * @sdev
569 *
570 */
571static void
572mptfc_dump_lun_info(MPT_ADAPTER *ioc, struct fc_rport *rport, struct scsi_device *sdev,
573 VirtTarget *vtarget)
574{
575 u64 nn, pn;
576 struct mptfc_rport_info *ri;
577
578 ri = *((struct mptfc_rport_info **)rport->dd_data);
579 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
580 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
581 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
582 "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
583 "CurrentTargetID %d, %x %llx %llx\n",
584 ioc->name,
585 sdev->host->host_no,
586 vtarget->num_luns,
587 sdev->id, ri->pg0.CurrentTargetID,
588 ri->pg0.PortIdentifier,
589 (unsigned long long)pn,
590 (unsigned long long)nn));
591}
592
Michael Reed3bc7bf12006-01-25 18:05:18 -0700593
594/*
Michael Reed05e8ec12006-01-13 14:31:54 -0600595 * OS entry point to allow host driver to alloc memory
596 * for each scsi device. Called once per device the bus scan.
597 * Return non-zero if allocation fails.
598 * Init memory once per LUN.
599 */
Adrian Bunk03fbcbc2006-01-25 02:00:52 +0100600static int
Michael Reed05e8ec12006-01-13 14:31:54 -0600601mptfc_slave_alloc(struct scsi_device *sdev)
602{
603 MPT_SCSI_HOST *hd;
604 VirtTarget *vtarget;
605 VirtDevice *vdev;
606 struct scsi_target *starget;
607 struct fc_rport *rport;
Michael Reed05e8ec12006-01-13 14:31:54 -0600608
609
Moore, Eric65207fe2006-04-21 16:14:35 -0600610 starget = scsi_target(sdev);
611 rport = starget_to_rport(starget);
Michael Reed05e8ec12006-01-13 14:31:54 -0600612
613 if (!rport || fc_remote_port_chkready(rport))
614 return -ENXIO;
615
616 hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
617
Michael Reed3bc7bf12006-01-25 18:05:18 -0700618 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Michael Reed05e8ec12006-01-13 14:31:54 -0600619 if (!vdev) {
620 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
621 hd->ioc->name, sizeof(VirtDevice));
622 return -ENOMEM;
623 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600624
Michael Reed05e8ec12006-01-13 14:31:54 -0600625
Michael Reed05e8ec12006-01-13 14:31:54 -0600626 sdev->hostdata = vdev;
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) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700630 vtarget->ioc_id = hd->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
Michael Reed05e8ec12006-01-13 14:31:54 -0600634 vdev->vtarget = vtarget;
Michael Reed05e8ec12006-01-13 14:31:54 -0600635 vdev->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
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530640 mptfc_dump_lun_info(hd->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 Moore793955f2007-01-29 09:42:20 -0700651 VirtDevice *vdev = SCpnt->device->hostdata;
Michael Reed05e8ec12006-01-13 14:31:54 -0600652
Eric Moore793955f2007-01-29 09:42:20 -0700653 if (!vdev || !vdev->vtarget) {
654 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/*
678 * mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
679 * @ioc: Pointer to MPT_ADAPTER structure
680 * @portnum: IOC Port number
681 *
682 * Return: 0 for success
683 * -ENOMEM if no memory available
684 * -EPERM if not allowed due to ISR context
685 * -EAGAIN if no msg frames currently available
686 * -EFAULT for non-successful reply or no reply (timeout)
687 * -EINVAL portnum arg out of range (hardwired to two elements)
688 */
689static int
690mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
691{
692 ConfigPageHeader_t hdr;
693 CONFIGPARMS cfg;
694 FCPortPage0_t *ppage0_alloc;
695 FCPortPage0_t *pp0dest;
696 dma_addr_t page0_dma;
697 int data_sz;
698 int copy_sz;
699 int rc;
700 int count = 400;
701
702 if (portnum > 1)
703 return -EINVAL;
704
705 /* Get FCPort Page 0 header */
706 hdr.PageVersion = 0;
707 hdr.PageLength = 0;
708 hdr.PageNumber = 0;
709 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
710 cfg.cfghdr.hdr = &hdr;
711 cfg.physAddr = -1;
712 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
713 cfg.dir = 0;
714 cfg.pageAddr = portnum;
715 cfg.timeout = 0;
716
717 if ((rc = mpt_config(ioc, &cfg)) != 0)
718 return rc;
719
720 if (hdr.PageLength == 0)
721 return 0;
722
723 data_sz = hdr.PageLength * 4;
724 rc = -ENOMEM;
725 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
726 if (ppage0_alloc) {
727
728 try_again:
729 memset((u8 *)ppage0_alloc, 0, data_sz);
730 cfg.physAddr = page0_dma;
731 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
732
733 if ((rc = mpt_config(ioc, &cfg)) == 0) {
734 /* save the data */
735 pp0dest = &ioc->fc_port_page0[portnum];
736 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
737 memcpy(pp0dest, ppage0_alloc, copy_sz);
738
739 /*
740 * Normalize endianness of structure data,
741 * by byte-swapping all > 1 byte fields!
742 */
743 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
744 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
745 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
746 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
747 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
748 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
749 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
750 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
751 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
752 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
753 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
754 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
755 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
756 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
757 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
758 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
759
760 /*
761 * if still doing discovery,
762 * hang loose a while until finished
763 */
Michael Reed77d88ee2006-07-31 12:19:40 -0500764 if ((pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) ||
765 (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE &&
766 (pp0dest->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK)
767 == MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT)) {
Michael Reed80d3ac72006-05-24 15:07:09 -0500768 if (count-- > 0) {
Michael Reedd6be06c2006-05-24 15:07:57 -0500769 msleep(100);
Michael Reed80d3ac72006-05-24 15:07:09 -0500770 goto try_again;
771 }
772 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
773 " complete.\n",
774 ioc->name);
775 }
776 }
777
778 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
779 }
780
781 return rc;
782}
783
Michael Reedca2f9382006-05-24 15:07:24 -0500784static int
785mptfc_WriteFcPortPage1(MPT_ADAPTER *ioc, int portnum)
786{
787 ConfigPageHeader_t hdr;
788 CONFIGPARMS cfg;
789 int rc;
790
791 if (portnum > 1)
792 return -EINVAL;
793
794 if (!(ioc->fc_data.fc_port_page1[portnum].data))
795 return -EINVAL;
796
797 /* get fcport page 1 header */
798 hdr.PageVersion = 0;
799 hdr.PageLength = 0;
800 hdr.PageNumber = 1;
801 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
802 cfg.cfghdr.hdr = &hdr;
803 cfg.physAddr = -1;
804 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
805 cfg.dir = 0;
806 cfg.pageAddr = portnum;
807 cfg.timeout = 0;
808
809 if ((rc = mpt_config(ioc, &cfg)) != 0)
810 return rc;
811
812 if (hdr.PageLength == 0)
813 return -ENODEV;
814
815 if (hdr.PageLength*4 != ioc->fc_data.fc_port_page1[portnum].pg_sz)
816 return -EINVAL;
817
818 cfg.physAddr = ioc->fc_data.fc_port_page1[portnum].dma;
819 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
820 cfg.dir = 1;
821
822 rc = mpt_config(ioc, &cfg);
823
824 return rc;
825}
826
827static int
828mptfc_GetFcPortPage1(MPT_ADAPTER *ioc, int portnum)
829{
830 ConfigPageHeader_t hdr;
831 CONFIGPARMS cfg;
832 FCPortPage1_t *page1_alloc;
833 dma_addr_t page1_dma;
834 int data_sz;
835 int rc;
836
837 if (portnum > 1)
838 return -EINVAL;
839
840 /* get fcport page 1 header */
841 hdr.PageVersion = 0;
842 hdr.PageLength = 0;
843 hdr.PageNumber = 1;
844 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
845 cfg.cfghdr.hdr = &hdr;
846 cfg.physAddr = -1;
847 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
848 cfg.dir = 0;
849 cfg.pageAddr = portnum;
850 cfg.timeout = 0;
851
852 if ((rc = mpt_config(ioc, &cfg)) != 0)
853 return rc;
854
855 if (hdr.PageLength == 0)
856 return -ENODEV;
857
858start_over:
859
860 if (ioc->fc_data.fc_port_page1[portnum].data == NULL) {
861 data_sz = hdr.PageLength * 4;
862 if (data_sz < sizeof(FCPortPage1_t))
863 data_sz = sizeof(FCPortPage1_t);
864
865 page1_alloc = (FCPortPage1_t *) pci_alloc_consistent(ioc->pcidev,
866 data_sz,
867 &page1_dma);
868 if (!page1_alloc)
869 return -ENOMEM;
870 }
871 else {
872 page1_alloc = ioc->fc_data.fc_port_page1[portnum].data;
873 page1_dma = ioc->fc_data.fc_port_page1[portnum].dma;
874 data_sz = ioc->fc_data.fc_port_page1[portnum].pg_sz;
875 if (hdr.PageLength * 4 > data_sz) {
876 ioc->fc_data.fc_port_page1[portnum].data = NULL;
877 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
878 page1_alloc, page1_dma);
879 goto start_over;
880 }
881 }
882
883 memset(page1_alloc,0,data_sz);
884
885 cfg.physAddr = page1_dma;
886 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
887
888 if ((rc = mpt_config(ioc, &cfg)) == 0) {
889 ioc->fc_data.fc_port_page1[portnum].data = page1_alloc;
890 ioc->fc_data.fc_port_page1[portnum].pg_sz = data_sz;
891 ioc->fc_data.fc_port_page1[portnum].dma = page1_dma;
892 }
893 else {
894 ioc->fc_data.fc_port_page1[portnum].data = NULL;
895 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
896 page1_alloc, page1_dma);
897 }
898
899 return rc;
900}
901
902static void
903mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
904{
905 int ii;
906 FCPortPage1_t *pp1;
907
908 #define MPTFC_FW_DEVICE_TIMEOUT (1)
909 #define MPTFC_FW_IO_PEND_TIMEOUT (1)
910 #define ON_FLAGS (MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY)
911 #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)
912
913 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
914 if (mptfc_GetFcPortPage1(ioc, ii) != 0)
915 continue;
916 pp1 = ioc->fc_data.fc_port_page1[ii].data;
917 if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)
918 && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)
919 && ((pp1->Flags & ON_FLAGS) == ON_FLAGS)
920 && ((pp1->Flags & OFF_FLAGS) == 0))
921 continue;
922 pp1->InitiatorDeviceTimeout = MPTFC_FW_DEVICE_TIMEOUT;
923 pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT;
924 pp1->Flags &= ~OFF_FLAGS;
925 pp1->Flags |= ON_FLAGS;
926 mptfc_WriteFcPortPage1(ioc, ii);
927 }
928}
929
930
Michael Reed05e8ec12006-01-13 14:31:54 -0600931static void
932mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
933{
Michael Reed5d947f22006-07-31 12:19:30 -0500934 unsigned class = 0;
935 unsigned cos = 0;
936 unsigned speed;
937 unsigned port_type;
938 unsigned port_state;
939 FCPortPage0_t *pp0;
940 struct Scsi_Host *sh;
941 char *sn;
Michael Reed05e8ec12006-01-13 14:31:54 -0600942
943 /* don't know what to do as only one scsi (fc) host was allocated */
944 if (portnum != 0)
945 return;
946
Michael Reed5d947f22006-07-31 12:19:30 -0500947 pp0 = &ioc->fc_port_page0[portnum];
948 sh = ioc->sh;
949
950 sn = fc_host_symbolic_name(sh);
951 snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",
952 ioc->prod_name,
953 MPT_FW_REV_MAGIC_ID_STRING,
954 ioc->facts.FWVersion.Word);
955
956 fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;
957
958 fc_host_maxframe_size(sh) = pp0->MaxFrameSize;
959
960 fc_host_node_name(sh) =
961 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
962
963 fc_host_port_name(sh) =
964 (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;
965
966 fc_host_port_id(sh) = pp0->PortIdentifier;
967
968 class = pp0->SupportedServiceClass;
Michael Reed05e8ec12006-01-13 14:31:54 -0600969 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
970 cos |= FC_COS_CLASS1;
971 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
972 cos |= FC_COS_CLASS2;
973 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
974 cos |= FC_COS_CLASS3;
Michael Reed5d947f22006-07-31 12:19:30 -0500975 fc_host_supported_classes(sh) = cos;
Michael Reed05e8ec12006-01-13 14:31:54 -0600976
Michael Reed5d947f22006-07-31 12:19:30 -0500977 if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)
978 speed = FC_PORTSPEED_1GBIT;
979 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)
980 speed = FC_PORTSPEED_2GBIT;
981 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)
982 speed = FC_PORTSPEED_4GBIT;
983 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)
984 speed = FC_PORTSPEED_10GBIT;
985 else
986 speed = FC_PORTSPEED_UNKNOWN;
987 fc_host_speed(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -0600988
Michael Reed5d947f22006-07-31 12:19:30 -0500989 speed = 0;
990 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)
991 speed |= FC_PORTSPEED_1GBIT;
992 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
993 speed |= FC_PORTSPEED_2GBIT;
994 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
995 speed |= FC_PORTSPEED_4GBIT;
996 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
997 speed |= FC_PORTSPEED_10GBIT;
998 fc_host_supported_speeds(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -0600999
Michael Reed5d947f22006-07-31 12:19:30 -05001000 port_state = FC_PORTSTATE_UNKNOWN;
1001 if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)
1002 port_state = FC_PORTSTATE_ONLINE;
1003 else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)
1004 port_state = FC_PORTSTATE_LINKDOWN;
1005 fc_host_port_state(sh) = port_state;
Michael Reed05e8ec12006-01-13 14:31:54 -06001006
Michael Reed5d947f22006-07-31 12:19:30 -05001007 port_type = FC_PORTTYPE_UNKNOWN;
1008 if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)
1009 port_type = FC_PORTTYPE_PTP;
1010 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)
1011 port_type = FC_PORTTYPE_LPORT;
1012 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)
1013 port_type = FC_PORTTYPE_NLPORT;
1014 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)
1015 port_type = FC_PORTTYPE_NPORT;
1016 fc_host_port_type(sh) = port_type;
Michael Reed05e8ec12006-01-13 14:31:54 -06001017
Michael Reed5d947f22006-07-31 12:19:30 -05001018 fc_host_fabric_name(sh) =
1019 (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?
1020 (u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :
1021 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
1022
Michael Reed05e8ec12006-01-13 14:31:54 -06001023}
1024
1025static void
David Howellsc4028952006-11-22 14:57:56 +00001026mptfc_setup_reset(struct work_struct *work)
Michael Reed419835e2006-05-24 15:07:40 -05001027{
David Howellsc4028952006-11-22 14:57:56 +00001028 MPT_ADAPTER *ioc =
1029 container_of(work, MPT_ADAPTER, fc_setup_reset_work);
Michael Reed419835e2006-05-24 15:07:40 -05001030 u64 pn;
1031 struct mptfc_rport_info *ri;
1032
1033 /* reset about to happen, delete (block) all rports */
1034 list_for_each_entry(ri, &ioc->fc_rports, list) {
1035 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1036 ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
1037 fc_remote_port_delete(ri->rport); /* won't sleep */
1038 ri->rport = NULL;
1039
1040 pn = (u64)ri->pg0.WWPN.High << 32 |
1041 (u64)ri->pg0.WWPN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301042 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed419835e2006-05-24 15:07:40 -05001043 "mptfc_setup_reset.%d: %llx deleted\n",
1044 ioc->name,
1045 ioc->sh->host_no,
1046 (unsigned long long)pn));
1047 }
1048 }
1049}
1050
1051static void
David Howellsc4028952006-11-22 14:57:56 +00001052mptfc_rescan_devices(struct work_struct *work)
Michael Reed05e8ec12006-01-13 14:31:54 -06001053{
David Howellsc4028952006-11-22 14:57:56 +00001054 MPT_ADAPTER *ioc =
1055 container_of(work, MPT_ADAPTER, fc_rescan_work);
Michael Reed05e8ec12006-01-13 14:31:54 -06001056 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001057 u64 pn;
Michael Reed05e8ec12006-01-13 14:31:54 -06001058 struct mptfc_rport_info *ri;
1059
Michael Reed3a0c56d2006-07-31 12:19:50 -05001060 /* start by tagging all ports as missing */
1061 list_for_each_entry(ri, &ioc->fc_rports, list) {
1062 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1063 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
Michael Reed05e8ec12006-01-13 14:31:54 -06001064 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001065 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001066
Michael Reed3a0c56d2006-07-31 12:19:50 -05001067 /*
1068 * now rescan devices known to adapter,
1069 * will reregister existing rports
1070 */
1071 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1072 (void) mptfc_GetFcPortPage0(ioc, ii);
1073 mptfc_init_host_attr(ioc, ii); /* refresh */
1074 mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev);
1075 }
1076
1077 /* delete devices still missing */
1078 list_for_each_entry(ri, &ioc->fc_rports, list) {
1079 /* if newly missing, delete it */
1080 if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
1081
1082 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
1083 MPT_RPORT_INFO_FLAGS_MISSING);
1084 fc_remote_port_delete(ri->rport); /* won't sleep */
1085 ri->rport = NULL;
1086
1087 pn = (u64)ri->pg0.WWPN.High << 32 |
1088 (u64)ri->pg0.WWPN.Low;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301089 dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
Michael Reed3a0c56d2006-07-31 12:19:50 -05001090 "mptfc_rescan.%d: %llx deleted\n",
1091 ioc->name,
1092 ioc->sh->host_no,
1093 (unsigned long long)pn));
Michael Reed05e8ec12006-01-13 14:31:54 -06001094 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001095 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001096}
1097
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001098static int
1099mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1100{
1101 struct Scsi_Host *sh;
1102 MPT_SCSI_HOST *hd;
1103 MPT_ADAPTER *ioc;
1104 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001105 int ii;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001106 int numSGE = 0;
1107 int scale;
1108 int ioc_cap;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001109 int error=0;
1110 int r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001111
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001112 if ((r = mpt_attach(pdev,id)) != 0)
1113 return r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001114
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001115 ioc = pci_get_drvdata(pdev);
Moore, Eric Dean d335cc32005-04-30 17:09:38 -05001116 ioc->DoneCtx = mptfcDoneCtx;
1117 ioc->TaskCtx = mptfcTaskCtx;
1118 ioc->InternalCtx = mptfcInternalCtx;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001119
1120 /* Added sanity check on readiness of the MPT adapter.
1121 */
1122 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1123 printk(MYIOC_s_WARN_FMT
1124 "Skipping because it's not operational!\n",
1125 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001126 error = -ENODEV;
1127 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001128 }
1129
1130 if (!ioc->active) {
1131 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1132 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001133 error = -ENODEV;
1134 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001135 }
1136
1137 /* Sanity check - ensure at least 1 port is INITIATOR capable
1138 */
1139 ioc_cap = 0;
1140 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1141 if (ioc->pfacts[ii].ProtocolFlags &
1142 MPI_PORTFACTS_PROTOCOL_INITIATOR)
1143 ioc_cap ++;
1144 }
1145
1146 if (!ioc_cap) {
1147 printk(MYIOC_s_WARN_FMT
1148 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1149 ioc->name, ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001150 return 0;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001151 }
1152
1153 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
1154
1155 if (!sh) {
1156 printk(MYIOC_s_WARN_FMT
1157 "Unable to register controller with SCSI subsystem\n",
1158 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001159 error = -1;
1160 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001161 }
1162
Michael Reed80d3ac72006-05-24 15:07:09 -05001163 spin_lock_init(&ioc->fc_rescan_work_lock);
David Howellsc4028952006-11-22 14:57:56 +00001164 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
1165 INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
Michael Reed05e8ec12006-01-13 14:31:54 -06001166
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001167 spin_lock_irqsave(&ioc->FreeQlock, flags);
1168
1169 /* Attach the SCSI Host to the IOC structure
1170 */
1171 ioc->sh = sh;
1172
1173 sh->io_port = 0;
1174 sh->n_io_port = 0;
1175 sh->irq = 0;
1176
1177 /* set 16 byte cdb's */
1178 sh->max_cmd_len = 16;
1179
Eric Moore793955f2007-01-29 09:42:20 -07001180 sh->max_id = ioc->pfacts->MaxDevices;
1181 sh->max_lun = max_lun;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001182
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001183 sh->this_id = ioc->pfacts[0].PortSCSIID;
1184
1185 /* Required entry.
1186 */
1187 sh->unique_id = ioc->id;
1188
1189 /* Verify that we won't exceed the maximum
1190 * number of chain buffers
1191 * We can optimize: ZZ = req_sz/sizeof(SGE)
1192 * For 32bit SGE's:
1193 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1194 * + (req_sz - 64)/sizeof(SGE)
1195 * A slightly different algorithm is required for
1196 * 64bit SGEs.
1197 */
1198 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
1199 if (sizeof(dma_addr_t) == sizeof(u64)) {
1200 numSGE = (scale - 1) *
1201 (ioc->facts.MaxChainDepth-1) + scale +
1202 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
1203 sizeof(u32));
1204 } else {
1205 numSGE = 1 + (scale - 1) *
1206 (ioc->facts.MaxChainDepth-1) + scale +
1207 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
1208 sizeof(u32));
1209 }
1210
1211 if (numSGE < sh->sg_tablesize) {
1212 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301213 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001214 "Resetting sg_tablesize to %d from %d\n",
1215 ioc->name, numSGE, sh->sg_tablesize));
1216 sh->sg_tablesize = numSGE;
1217 }
1218
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001219 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1220
1221 hd = (MPT_SCSI_HOST *) sh->hostdata;
1222 hd->ioc = ioc;
1223
1224 /* SCSI needs scsi_cmnd lookup table!
1225 * (with size equal to req_depth*PtrSz!)
1226 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001227 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
1228 if (!hd->ScsiLookup) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001229 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001230 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001231 }
1232
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301233 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001234 ioc->name, hd->ScsiLookup));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001235
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001236 /* Clear the TM flags
1237 */
1238 hd->tmPending = 0;
1239 hd->tmState = TM_STATE_NONE;
1240 hd->resetPending = 0;
1241 hd->abortSCpnt = NULL;
1242
1243 /* Clear the pointer used to store
1244 * single-threaded commands, i.e., those
1245 * issued during a bus scan, dv and
1246 * configuration pages.
1247 */
1248 hd->cmdPtr = NULL;
1249
1250 /* Initialize this SCSI Hosts' timers
1251 * To use, set the timer expires field
1252 * and add_timer
1253 */
1254 init_timer(&hd->timer);
1255 hd->timer.data = (unsigned long) hd;
1256 hd->timer.function = mptscsih_timer_expired;
1257
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001258 init_waitqueue_head(&hd->scandv_waitq);
1259 hd->scandv_wait_done = 0;
1260 hd->last_queue_full = 0;
1261
Michael Reed05e8ec12006-01-13 14:31:54 -06001262 sh->transportt = mptfc_transport_template;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001263 error = scsi_add_host (sh, &ioc->pcidev->dev);
1264 if(error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301265 dprintk(ioc, printk(KERN_ERR MYNAM
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001266 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001267 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001268 }
1269
Moore, Eric65207fe2006-04-21 16:14:35 -06001270 /* initialize workqueue */
1271
1272 snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d",
1273 sh->host_no);
1274 ioc->fc_rescan_work_q =
1275 create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
1276 if (!ioc->fc_rescan_work_q)
1277 goto out_mptfc_probe;
1278
1279 /*
Michael Reed80d3ac72006-05-24 15:07:09 -05001280 * Pre-fetch FC port WWN and stuff...
1281 * (FCPortPage0_t stuff)
1282 */
1283 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1284 (void) mptfc_GetFcPortPage0(ioc, ii);
1285 }
Michael Reedca2f9382006-05-24 15:07:24 -05001286 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001287
1288 /*
Moore, Eric65207fe2006-04-21 16:14:35 -06001289 * scan for rports -
1290 * by doing it via the workqueue, some locking is eliminated
1291 */
1292
Moore, Eric65207fe2006-04-21 16:14:35 -06001293 queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
1294 flush_workqueue(ioc->fc_rescan_work_q);
Michael Reed05e8ec12006-01-13 14:31:54 -06001295
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001296 return 0;
1297
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001298out_mptfc_probe:
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001299
1300 mptscsih_remove(pdev);
1301 return error;
1302}
1303
1304static struct pci_driver mptfc_driver = {
1305 .name = "mptfc",
1306 .id_table = mptfc_pci_table,
1307 .probe = mptfc_probe,
Michael Reed05e8ec12006-01-13 14:31:54 -06001308 .remove = __devexit_p(mptfc_remove),
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001309 .shutdown = mptscsih_shutdown,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001310#ifdef CONFIG_PM
1311 .suspend = mptscsih_suspend,
1312 .resume = mptscsih_resume,
1313#endif
1314};
1315
Michael Reed80d3ac72006-05-24 15:07:09 -05001316static int
1317mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1318{
1319 MPT_SCSI_HOST *hd;
1320 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1321 unsigned long flags;
1322 int rc=1;
1323
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301324 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Michael Reed80d3ac72006-05-24 15:07:09 -05001325 ioc->name, event));
1326
1327 if (ioc->sh == NULL ||
1328 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
1329 return 1;
1330
1331 switch (event) {
1332 case MPI_EVENT_RESCAN:
1333 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1334 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001335 queue_work(ioc->fc_rescan_work_q,
1336 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001337 }
1338 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1339 break;
1340 default:
1341 rc = mptscsih_event_process(ioc,pEvReply);
1342 break;
1343 }
1344 return rc;
1345}
1346
1347static int
1348mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1349{
1350 int rc;
1351 unsigned long flags;
1352
1353 rc = mptscsih_ioc_reset(ioc,reset_phase);
1354 if (rc == 0)
1355 return rc;
1356
1357
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301358 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1359 ": IOC %s_reset routed to FC host driver!\n",ioc->name,
Michael Reed80d3ac72006-05-24 15:07:09 -05001360 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
1361 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
1362
1363 if (reset_phase == MPT_IOC_SETUP_RESET) {
Michael Reed419835e2006-05-24 15:07:40 -05001364 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1365 if (ioc->fc_rescan_work_q) {
1366 queue_work(ioc->fc_rescan_work_q,
1367 &ioc->fc_setup_reset_work);
1368 }
1369 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
Michael Reed80d3ac72006-05-24 15:07:09 -05001370 }
1371
1372 else if (reset_phase == MPT_IOC_PRE_RESET) {
1373 }
1374
1375 else { /* MPT_IOC_POST_RESET */
Michael Reedca2f9382006-05-24 15:07:24 -05001376 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001377 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1378 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001379 queue_work(ioc->fc_rescan_work_q,
1380 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001381 }
1382 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1383 }
1384 return 1;
1385}
1386
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001387/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1388/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001389 * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001390 *
1391 * Returns 0 for success, non-zero for failure.
1392 */
1393static int __init
1394mptfc_init(void)
1395{
Michael Reed05e8ec12006-01-13 14:31:54 -06001396 int error;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001397
1398 show_mptmod_ver(my_NAME, my_VERSION);
1399
Michael Reedca2f9382006-05-24 15:07:24 -05001400 /* sanity check module parameters */
1401 if (mptfc_dev_loss_tmo <= 0)
Michael Reed05e8ec12006-01-13 14:31:54 -06001402 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
1403
1404 mptfc_transport_template =
1405 fc_attach_transport(&mptfc_transport_functions);
1406
1407 if (!mptfc_transport_template)
1408 return -ENODEV;
1409
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001410 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
1411 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
1412 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
1413
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301414 mpt_event_register(mptfcDoneCtx, mptfc_event_process);
1415 mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001416
Michael Reed05e8ec12006-01-13 14:31:54 -06001417 error = pci_register_driver(&mptfc_driver);
Michael Reed3bc7bf12006-01-25 18:05:18 -07001418 if (error)
Michael Reed05e8ec12006-01-13 14:31:54 -06001419 fc_release_transport(mptfc_transport_template);
Michael Reed05e8ec12006-01-13 14:31:54 -06001420
1421 return error;
1422}
1423
1424/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1425/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001426 * mptfc_remove - Remove fc infrastructure for devices
Michael Reed05e8ec12006-01-13 14:31:54 -06001427 * @pdev: Pointer to pci_dev structure
1428 *
1429 */
Michael Reed3bc7bf12006-01-25 18:05:18 -07001430static void __devexit
1431mptfc_remove(struct pci_dev *pdev)
Michael Reed05e8ec12006-01-13 14:31:54 -06001432{
Moore, Eric65207fe2006-04-21 16:14:35 -06001433 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1434 struct mptfc_rport_info *p, *n;
1435 struct workqueue_struct *work_q;
1436 unsigned long flags;
Michael Reedca2f9382006-05-24 15:07:24 -05001437 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001438
1439 /* destroy workqueue */
1440 if ((work_q=ioc->fc_rescan_work_q)) {
1441 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1442 ioc->fc_rescan_work_q = NULL;
1443 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1444 destroy_workqueue(work_q);
1445 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001446
1447 fc_remove_host(ioc->sh);
1448
1449 list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
1450 list_del(&p->list);
1451 kfree(p);
1452 }
1453
Michael Reedca2f9382006-05-24 15:07:24 -05001454 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
1455 if (ioc->fc_data.fc_port_page1[ii].data) {
1456 pci_free_consistent(ioc->pcidev,
1457 ioc->fc_data.fc_port_page1[ii].pg_sz,
1458 (u8 *) ioc->fc_data.fc_port_page1[ii].data,
1459 ioc->fc_data.fc_port_page1[ii].dma);
1460 ioc->fc_data.fc_port_page1[ii].data = NULL;
1461 }
1462 }
1463
Michael Reed05e8ec12006-01-13 14:31:54 -06001464 mptscsih_remove(pdev);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001465}
1466
1467/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1468/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1469/**
1470 * mptfc_exit - Unregisters MPT adapter(s)
1471 *
1472 */
1473static void __exit
1474mptfc_exit(void)
1475{
1476 pci_unregister_driver(&mptfc_driver);
Michael Reed05e8ec12006-01-13 14:31:54 -06001477 fc_release_transport(mptfc_transport_template);
1478
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001479 mpt_reset_deregister(mptfcDoneCtx);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001480 mpt_event_deregister(mptfcDoneCtx);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001481
1482 mpt_deregister(mptfcInternalCtx);
1483 mpt_deregister(mptfcTaskCtx);
1484 mpt_deregister(mptfcDoneCtx);
1485}
1486
1487module_init(mptfc_init);
1488module_exit(mptfc_exit);