blob: f2ebaa9992febc19cee852c63542fe62b6f494f6 [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{
191 struct scsi_device *sdev = SCpnt->device;
192 struct Scsi_Host *shost = sdev->host;
193 struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
194 unsigned long flags;
195 int ready;
196
197 spin_lock_irqsave(shost->host_lock, flags);
198 while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
199 spin_unlock_irqrestore(shost->host_lock, flags);
200 dfcprintk ((MYIOC_s_INFO_FMT
201 "mptfc_block_error_handler.%d: %d:%d, port status is "
202 "DID_IMM_RETRY, deferring %s recovery.\n",
203 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
204 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
205 SCpnt->device->id,SCpnt->device->lun,caller));
206 msleep(1000);
207 spin_lock_irqsave(shost->host_lock, flags);
208 }
209 spin_unlock_irqrestore(shost->host_lock, flags);
210
211 if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
212 dfcprintk ((MYIOC_s_INFO_FMT
213 "%s.%d: %d:%d, failing recovery, "
214 "port state %d, vdev %p.\n", caller,
215 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
216 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
217 SCpnt->device->id,SCpnt->device->lun,ready,
218 SCpnt->device->hostdata));
219 return FAILED;
220 }
221 dfcprintk ((MYIOC_s_INFO_FMT
222 "%s.%d: %d:%d, executing recovery.\n", caller,
223 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
224 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
225 SCpnt->device->id,SCpnt->device->lun));
226 return (*func)(SCpnt);
227}
228
229static int
230mptfc_abort(struct scsi_cmnd *SCpnt)
231{
232 return
233 mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
234}
235
236static int
237mptfc_dev_reset(struct scsi_cmnd *SCpnt)
238{
239 return
240 mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
241}
242
243static int
244mptfc_bus_reset(struct scsi_cmnd *SCpnt)
245{
246 return
247 mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
248}
249
250static int
251mptfc_host_reset(struct scsi_cmnd *SCpnt)
252{
253 return
254 mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
255}
256
Michael Reed05e8ec12006-01-13 14:31:54 -0600257static void
258mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
259{
260 if (timeout > 0)
261 rport->dev_loss_tmo = timeout;
262 else
263 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
264}
265
266static int
267mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
268{
269 FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
270 FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
271
272 if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
273 if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
274 return 0;
275 if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
276 return -1;
277 return 1;
278 }
279 if ((*aa)->CurrentBus < (*bb)->CurrentBus)
280 return -1;
281 return 1;
282}
283
284static int
285mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
286 void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
287{
288 ConfigPageHeader_t hdr;
289 CONFIGPARMS cfg;
290 FCDevicePage0_t *ppage0_alloc, *fc;
291 dma_addr_t page0_dma;
292 int data_sz;
293 int ii;
294
295 FCDevicePage0_t *p0_array=NULL, *p_p0;
296 FCDevicePage0_t **pp0_array=NULL, **p_pp0;
297
298 int rc = -ENOMEM;
299 U32 port_id = 0xffffff;
300 int num_targ = 0;
301 int max_bus = ioc->facts.MaxBuses;
Eric Moore793955f2007-01-29 09:42:20 -0700302 int max_targ;
Michael Reed05e8ec12006-01-13 14:31:54 -0600303
Eric Moore793955f2007-01-29 09:42:20 -0700304 max_targ = (ioc->facts.MaxDevices == 0) ? 256 : ioc->facts.MaxDevices;
Michael Reed05e8ec12006-01-13 14:31:54 -0600305
306 data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
307 p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL);
308 if (!p0_array)
309 goto out;
310
311 data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
312 p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
313 if (!pp0_array)
314 goto out;
315
316 do {
317 /* Get FC Device Page 0 header */
318 hdr.PageVersion = 0;
319 hdr.PageLength = 0;
320 hdr.PageNumber = 0;
321 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
322 cfg.cfghdr.hdr = &hdr;
323 cfg.physAddr = -1;
324 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
325 cfg.dir = 0;
326 cfg.pageAddr = port_id;
327 cfg.timeout = 0;
328
329 if ((rc = mpt_config(ioc, &cfg)) != 0)
330 break;
331
332 if (hdr.PageLength <= 0)
333 break;
334
335 data_sz = hdr.PageLength * 4;
336 ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
337 &page0_dma);
338 rc = -ENOMEM;
339 if (!ppage0_alloc)
340 break;
341
342 cfg.physAddr = page0_dma;
343 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
344
345 if ((rc = mpt_config(ioc, &cfg)) == 0) {
346 ppage0_alloc->PortIdentifier =
347 le32_to_cpu(ppage0_alloc->PortIdentifier);
348
349 ppage0_alloc->WWNN.Low =
350 le32_to_cpu(ppage0_alloc->WWNN.Low);
351
352 ppage0_alloc->WWNN.High =
353 le32_to_cpu(ppage0_alloc->WWNN.High);
354
355 ppage0_alloc->WWPN.Low =
356 le32_to_cpu(ppage0_alloc->WWPN.Low);
357
358 ppage0_alloc->WWPN.High =
359 le32_to_cpu(ppage0_alloc->WWPN.High);
360
361 ppage0_alloc->BBCredit =
362 le16_to_cpu(ppage0_alloc->BBCredit);
363
364 ppage0_alloc->MaxRxFrameSize =
365 le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
366
367 port_id = ppage0_alloc->PortIdentifier;
368 num_targ++;
369 *p_p0 = *ppage0_alloc; /* save data */
370 *p_pp0++ = p_p0++; /* save addr */
371 }
372 pci_free_consistent(ioc->pcidev, data_sz,
373 (u8 *) ppage0_alloc, page0_dma);
374 if (rc != 0)
375 break;
376
377 } while (port_id <= 0xff0000);
378
379 if (num_targ) {
380 /* sort array */
381 if (num_targ > 1)
382 sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
383 mptfc_FcDevPage0_cmp_func, NULL);
384 /* call caller's func for each targ */
385 for (ii = 0; ii < num_targ; ii++) {
386 fc = *(pp0_array+ii);
387 func(ioc, ioc_port, fc);
388 }
389 }
390
391 out:
Jesper Juhl8f760782006-06-27 02:55:06 -0700392 kfree(pp0_array);
393 kfree(p0_array);
Michael Reed05e8ec12006-01-13 14:31:54 -0600394 return rc;
395}
396
397static int
398mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
399{
400 /* not currently usable */
401 if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
402 MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
403 return -1;
404
405 if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
406 return -1;
407
408 if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
409 return -1;
410
411 /*
412 * board data structure already normalized to platform endianness
413 * shifted to avoid unaligned access on 64 bit architecture
414 */
415 rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
416 rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
417 rid->port_id = pg0->PortIdentifier;
418 rid->roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600419
420 return 0;
421}
422
423static void
424mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
425{
426 struct fc_rport_identifiers rport_ids;
427 struct fc_rport *rport;
428 struct mptfc_rport_info *ri;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700429 int new_ri = 1;
Moore, Eric65207fe2006-04-21 16:14:35 -0600430 u64 pn, nn;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700431 VirtTarget *vtarget;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500432 u32 roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600433
434 if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
435 return;
436
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500437 roles |= FC_RPORT_ROLE_FCP_TARGET;
438 if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
439 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
440
Michael Reed05e8ec12006-01-13 14:31:54 -0600441 /* scan list looking for a match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600442 list_for_each_entry(ri, &ioc->fc_rports, list) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700443 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
444 if (pn == rport_ids.port_name) { /* match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600445 list_move_tail(&ri->list, &ioc->fc_rports);
Michael Reed3bc7bf12006-01-25 18:05:18 -0700446 new_ri = 0;
Michael Reed05e8ec12006-01-13 14:31:54 -0600447 break;
448 }
449 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700450 if (new_ri) { /* allocate one */
Michael Reed05e8ec12006-01-13 14:31:54 -0600451 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
452 if (!ri)
453 return;
Michael Reed05e8ec12006-01-13 14:31:54 -0600454 list_add_tail(&ri->list, &ioc->fc_rports);
455 }
456
457 ri->pg0 = *pg0; /* add/update pg0 data */
458 ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
459
Michael Reed3bc7bf12006-01-25 18:05:18 -0700460 /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
Michael Reed05e8ec12006-01-13 14:31:54 -0600461 if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
462 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700463 rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
Michael Reed05e8ec12006-01-13 14:31:54 -0600464 if (rport) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700465 ri->rport = rport;
466 if (new_ri) /* may have been reset by user */
467 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
Michael Reed05e8ec12006-01-13 14:31:54 -0600468 /*
469 * if already mapped, remap here. If not mapped,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700470 * target_alloc will allocate vtarget and map,
471 * slave_alloc will fill in vdev from vtarget.
Michael Reed05e8ec12006-01-13 14:31:54 -0600472 */
Michael Reed3bc7bf12006-01-25 18:05:18 -0700473 if (ri->starget) {
474 vtarget = ri->starget->hostdata;
475 if (vtarget) {
Eric Moore793955f2007-01-29 09:42:20 -0700476 vtarget->id = pg0->CurrentTargetID;
477 vtarget->channel = pg0->CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700478 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600479 }
Moore, Eric65207fe2006-04-21 16:14:35 -0600480 *((struct mptfc_rport_info **)rport->dd_data) = ri;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500481 /* scan will be scheduled once rport becomes a target */
482 fc_remote_port_rolechg(rport,roles);
Moore, Eric65207fe2006-04-21 16:14:35 -0600483
484 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
485 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700486 dfcprintk ((MYIOC_s_INFO_FMT
487 "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600488 "rport tid %d, tmo %d\n",
Michael Reed3bc7bf12006-01-25 18:05:18 -0700489 ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700490 ioc->sh->host_no,
Michael Reed05e8ec12006-01-13 14:31:54 -0600491 pg0->PortIdentifier,
Moore, Eric65207fe2006-04-21 16:14:35 -0600492 (unsigned long long)nn,
493 (unsigned long long)pn,
Michael Reed05e8ec12006-01-13 14:31:54 -0600494 pg0->CurrentTargetID,
495 ri->rport->scsi_target_id,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700496 ri->rport->dev_loss_tmo));
Michael Reed05e8ec12006-01-13 14:31:54 -0600497 } else {
498 list_del(&ri->list);
499 kfree(ri);
500 ri = NULL;
501 }
502 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600503}
504
505/*
Michael Reed3bc7bf12006-01-25 18:05:18 -0700506 * OS entry point to allow for host driver to free allocated memory
507 * Called if no device present or device being unloaded
508 */
509static void
510mptfc_target_destroy(struct scsi_target *starget)
511{
512 struct fc_rport *rport;
513 struct mptfc_rport_info *ri;
514
515 rport = starget_to_rport(starget);
516 if (rport) {
517 ri = *((struct mptfc_rport_info **)rport->dd_data);
518 if (ri) /* better be! */
519 ri->starget = NULL;
520 }
521 if (starget->hostdata)
522 kfree(starget->hostdata);
523 starget->hostdata = NULL;
524}
525
526/*
527 * OS entry point to allow host driver to alloc memory
528 * for each scsi target. Called once per device the bus scan.
529 * Return non-zero if allocation fails.
530 */
531static int
532mptfc_target_alloc(struct scsi_target *starget)
533{
534 VirtTarget *vtarget;
535 struct fc_rport *rport;
536 struct mptfc_rport_info *ri;
537 int rc;
538
539 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
540 if (!vtarget)
541 return -ENOMEM;
542 starget->hostdata = vtarget;
543
544 rc = -ENODEV;
545 rport = starget_to_rport(starget);
546 if (rport) {
547 ri = *((struct mptfc_rport_info **)rport->dd_data);
548 if (ri) { /* better be! */
Eric Moore793955f2007-01-29 09:42:20 -0700549 vtarget->id = ri->pg0.CurrentTargetID;
550 vtarget->channel = ri->pg0.CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700551 ri->starget = starget;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700552 rc = 0;
553 }
554 }
555 if (rc != 0) {
556 kfree(vtarget);
557 starget->hostdata = NULL;
558 }
559
560 return rc;
561}
562
563/*
Michael Reed05e8ec12006-01-13 14:31:54 -0600564 * OS entry point to allow host driver to alloc memory
565 * for each scsi device. Called once per device the bus scan.
566 * Return non-zero if allocation fails.
567 * Init memory once per LUN.
568 */
Adrian Bunk03fbcbc2006-01-25 02:00:52 +0100569static int
Michael Reed05e8ec12006-01-13 14:31:54 -0600570mptfc_slave_alloc(struct scsi_device *sdev)
571{
572 MPT_SCSI_HOST *hd;
573 VirtTarget *vtarget;
574 VirtDevice *vdev;
575 struct scsi_target *starget;
576 struct fc_rport *rport;
Michael Reed05e8ec12006-01-13 14:31:54 -0600577
578
Moore, Eric65207fe2006-04-21 16:14:35 -0600579 starget = scsi_target(sdev);
580 rport = starget_to_rport(starget);
Michael Reed05e8ec12006-01-13 14:31:54 -0600581
582 if (!rport || fc_remote_port_chkready(rport))
583 return -ENXIO;
584
585 hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
586
Michael Reed3bc7bf12006-01-25 18:05:18 -0700587 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Michael Reed05e8ec12006-01-13 14:31:54 -0600588 if (!vdev) {
589 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
590 hd->ioc->name, sizeof(VirtDevice));
591 return -ENOMEM;
592 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600593
Michael Reed05e8ec12006-01-13 14:31:54 -0600594
Michael Reed05e8ec12006-01-13 14:31:54 -0600595 sdev->hostdata = vdev;
Michael Reed05e8ec12006-01-13 14:31:54 -0600596 vtarget = starget->hostdata;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700597
Michael Reed05e8ec12006-01-13 14:31:54 -0600598 if (vtarget->num_luns == 0) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700599 vtarget->ioc_id = hd->ioc->id;
Eric Mooreba856d32006-07-11 17:34:01 -0600600 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
Michael Reed05e8ec12006-01-13 14:31:54 -0600601 }
602
Michael Reed05e8ec12006-01-13 14:31:54 -0600603 vdev->vtarget = vtarget;
Michael Reed05e8ec12006-01-13 14:31:54 -0600604 vdev->lun = sdev->lun;
Michael Reed05e8ec12006-01-13 14:31:54 -0600605
Michael Reed05e8ec12006-01-13 14:31:54 -0600606 vtarget->num_luns++;
607
Moore, Eric65207fe2006-04-21 16:14:35 -0600608
Moore, Eric914c2d82006-03-14 09:19:36 -0700609#ifdef DMPT_DEBUG_FC
Moore, Eric65207fe2006-04-21 16:14:35 -0600610 {
611 u64 nn, pn;
Moore, Eric914c2d82006-03-14 09:19:36 -0700612 struct mptfc_rport_info *ri;
613 ri = *((struct mptfc_rport_info **)rport->dd_data);
Moore, Eric65207fe2006-04-21 16:14:35 -0600614 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
615 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700616 dfcprintk ((MYIOC_s_INFO_FMT
617 "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600618 "CurrentTargetID %d, %x %llx %llx\n",
Moore, Eric914c2d82006-03-14 09:19:36 -0700619 hd->ioc->name,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700620 sdev->host->host_no,
621 vtarget->num_luns,
622 sdev->id, ri->pg0.CurrentTargetID,
Moore, Eric65207fe2006-04-21 16:14:35 -0600623 ri->pg0.PortIdentifier,
624 (unsigned long long)pn,
625 (unsigned long long)nn));
Moore, Eric914c2d82006-03-14 09:19:36 -0700626 }
627#endif
Michael Reed05e8ec12006-01-13 14:31:54 -0600628
629 return 0;
630}
631
632static int
633mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
634{
Michael Reed3bc7bf12006-01-25 18:05:18 -0700635 struct mptfc_rport_info *ri;
Michael Reed05e8ec12006-01-13 14:31:54 -0600636 struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
637 int err;
Eric Moore793955f2007-01-29 09:42:20 -0700638 VirtDevice *vdev = SCpnt->device->hostdata;
Michael Reed05e8ec12006-01-13 14:31:54 -0600639
Eric Moore793955f2007-01-29 09:42:20 -0700640 if (!vdev || !vdev->vtarget) {
641 SCpnt->result = DID_NO_CONNECT << 16;
Michael Reed05e8ec12006-01-13 14:31:54 -0600642 done(SCpnt);
643 return 0;
644 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700645
Eric Moore793955f2007-01-29 09:42:20 -0700646 err = fc_remote_port_chkready(rport);
647 if (unlikely(err)) {
648 SCpnt->result = err;
Michael Reed35508e42006-10-06 15:39:25 -0500649 done(SCpnt);
650 return 0;
651 }
652
Moore, Eric65207fe2006-04-21 16:14:35 -0600653 /* dd_data is null until finished adding target */
654 ri = *((struct mptfc_rport_info **)rport->dd_data);
655 if (unlikely(!ri)) {
656 dfcprintk ((MYIOC_s_INFO_FMT
657 "mptfc_qcmd.%d: %d:%d, dd_data is null.\n",
658 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
659 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
660 SCpnt->device->id,SCpnt->device->lun));
661 SCpnt->result = DID_IMM_RETRY << 16;
662 done(SCpnt);
663 return 0;
664 }
665
666 err = mptscsih_qcmd(SCpnt,done);
667#ifdef DMPT_DEBUG_FC
668 if (unlikely(err)) {
669 dfcprintk ((MYIOC_s_INFO_FMT
Michael Reed419835e2006-05-24 15:07:40 -0500670 "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero, (%x).\n",
Moore, Eric65207fe2006-04-21 16:14:35 -0600671 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
672 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
Michael Reed419835e2006-05-24 15:07:40 -0500673 SCpnt->device->id,SCpnt->device->lun,err));
Moore, Eric65207fe2006-04-21 16:14:35 -0600674 }
675#endif
676 return err;
Michael Reed05e8ec12006-01-13 14:31:54 -0600677}
678
Michael Reed80d3ac72006-05-24 15:07:09 -0500679/*
680 * mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
681 * @ioc: Pointer to MPT_ADAPTER structure
682 * @portnum: IOC Port number
683 *
684 * Return: 0 for success
685 * -ENOMEM if no memory available
686 * -EPERM if not allowed due to ISR context
687 * -EAGAIN if no msg frames currently available
688 * -EFAULT for non-successful reply or no reply (timeout)
689 * -EINVAL portnum arg out of range (hardwired to two elements)
690 */
691static int
692mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
693{
694 ConfigPageHeader_t hdr;
695 CONFIGPARMS cfg;
696 FCPortPage0_t *ppage0_alloc;
697 FCPortPage0_t *pp0dest;
698 dma_addr_t page0_dma;
699 int data_sz;
700 int copy_sz;
701 int rc;
702 int count = 400;
703
704 if (portnum > 1)
705 return -EINVAL;
706
707 /* Get FCPort Page 0 header */
708 hdr.PageVersion = 0;
709 hdr.PageLength = 0;
710 hdr.PageNumber = 0;
711 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
712 cfg.cfghdr.hdr = &hdr;
713 cfg.physAddr = -1;
714 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
715 cfg.dir = 0;
716 cfg.pageAddr = portnum;
717 cfg.timeout = 0;
718
719 if ((rc = mpt_config(ioc, &cfg)) != 0)
720 return rc;
721
722 if (hdr.PageLength == 0)
723 return 0;
724
725 data_sz = hdr.PageLength * 4;
726 rc = -ENOMEM;
727 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
728 if (ppage0_alloc) {
729
730 try_again:
731 memset((u8 *)ppage0_alloc, 0, data_sz);
732 cfg.physAddr = page0_dma;
733 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
734
735 if ((rc = mpt_config(ioc, &cfg)) == 0) {
736 /* save the data */
737 pp0dest = &ioc->fc_port_page0[portnum];
738 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
739 memcpy(pp0dest, ppage0_alloc, copy_sz);
740
741 /*
742 * Normalize endianness of structure data,
743 * by byte-swapping all > 1 byte fields!
744 */
745 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
746 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
747 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
748 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
749 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
750 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
751 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
752 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
753 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
754 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
755 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
756 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
757 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
758 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
759 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
760 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
761
762 /*
763 * if still doing discovery,
764 * hang loose a while until finished
765 */
Michael Reed77d88ee2006-07-31 12:19:40 -0500766 if ((pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) ||
767 (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE &&
768 (pp0dest->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK)
769 == MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT)) {
Michael Reed80d3ac72006-05-24 15:07:09 -0500770 if (count-- > 0) {
Michael Reedd6be06c2006-05-24 15:07:57 -0500771 msleep(100);
Michael Reed80d3ac72006-05-24 15:07:09 -0500772 goto try_again;
773 }
774 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
775 " complete.\n",
776 ioc->name);
777 }
778 }
779
780 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
781 }
782
783 return rc;
784}
785
Michael Reedca2f9382006-05-24 15:07:24 -0500786static int
787mptfc_WriteFcPortPage1(MPT_ADAPTER *ioc, int portnum)
788{
789 ConfigPageHeader_t hdr;
790 CONFIGPARMS cfg;
791 int rc;
792
793 if (portnum > 1)
794 return -EINVAL;
795
796 if (!(ioc->fc_data.fc_port_page1[portnum].data))
797 return -EINVAL;
798
799 /* get fcport page 1 header */
800 hdr.PageVersion = 0;
801 hdr.PageLength = 0;
802 hdr.PageNumber = 1;
803 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
804 cfg.cfghdr.hdr = &hdr;
805 cfg.physAddr = -1;
806 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
807 cfg.dir = 0;
808 cfg.pageAddr = portnum;
809 cfg.timeout = 0;
810
811 if ((rc = mpt_config(ioc, &cfg)) != 0)
812 return rc;
813
814 if (hdr.PageLength == 0)
815 return -ENODEV;
816
817 if (hdr.PageLength*4 != ioc->fc_data.fc_port_page1[portnum].pg_sz)
818 return -EINVAL;
819
820 cfg.physAddr = ioc->fc_data.fc_port_page1[portnum].dma;
821 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
822 cfg.dir = 1;
823
824 rc = mpt_config(ioc, &cfg);
825
826 return rc;
827}
828
829static int
830mptfc_GetFcPortPage1(MPT_ADAPTER *ioc, int portnum)
831{
832 ConfigPageHeader_t hdr;
833 CONFIGPARMS cfg;
834 FCPortPage1_t *page1_alloc;
835 dma_addr_t page1_dma;
836 int data_sz;
837 int rc;
838
839 if (portnum > 1)
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
860start_over:
861
862 if (ioc->fc_data.fc_port_page1[portnum].data == NULL) {
863 data_sz = hdr.PageLength * 4;
864 if (data_sz < sizeof(FCPortPage1_t))
865 data_sz = sizeof(FCPortPage1_t);
866
867 page1_alloc = (FCPortPage1_t *) pci_alloc_consistent(ioc->pcidev,
868 data_sz,
869 &page1_dma);
870 if (!page1_alloc)
871 return -ENOMEM;
872 }
873 else {
874 page1_alloc = ioc->fc_data.fc_port_page1[portnum].data;
875 page1_dma = ioc->fc_data.fc_port_page1[portnum].dma;
876 data_sz = ioc->fc_data.fc_port_page1[portnum].pg_sz;
877 if (hdr.PageLength * 4 > data_sz) {
878 ioc->fc_data.fc_port_page1[portnum].data = NULL;
879 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
880 page1_alloc, page1_dma);
881 goto start_over;
882 }
883 }
884
885 memset(page1_alloc,0,data_sz);
886
887 cfg.physAddr = page1_dma;
888 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
889
890 if ((rc = mpt_config(ioc, &cfg)) == 0) {
891 ioc->fc_data.fc_port_page1[portnum].data = page1_alloc;
892 ioc->fc_data.fc_port_page1[portnum].pg_sz = data_sz;
893 ioc->fc_data.fc_port_page1[portnum].dma = page1_dma;
894 }
895 else {
896 ioc->fc_data.fc_port_page1[portnum].data = NULL;
897 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
898 page1_alloc, page1_dma);
899 }
900
901 return rc;
902}
903
904static void
905mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
906{
907 int ii;
908 FCPortPage1_t *pp1;
909
910 #define MPTFC_FW_DEVICE_TIMEOUT (1)
911 #define MPTFC_FW_IO_PEND_TIMEOUT (1)
912 #define ON_FLAGS (MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY)
913 #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)
914
915 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
916 if (mptfc_GetFcPortPage1(ioc, ii) != 0)
917 continue;
918 pp1 = ioc->fc_data.fc_port_page1[ii].data;
919 if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)
920 && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)
921 && ((pp1->Flags & ON_FLAGS) == ON_FLAGS)
922 && ((pp1->Flags & OFF_FLAGS) == 0))
923 continue;
924 pp1->InitiatorDeviceTimeout = MPTFC_FW_DEVICE_TIMEOUT;
925 pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT;
926 pp1->Flags &= ~OFF_FLAGS;
927 pp1->Flags |= ON_FLAGS;
928 mptfc_WriteFcPortPage1(ioc, ii);
929 }
930}
931
932
Michael Reed05e8ec12006-01-13 14:31:54 -0600933static void
934mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
935{
Michael Reed5d947f22006-07-31 12:19:30 -0500936 unsigned class = 0;
937 unsigned cos = 0;
938 unsigned speed;
939 unsigned port_type;
940 unsigned port_state;
941 FCPortPage0_t *pp0;
942 struct Scsi_Host *sh;
943 char *sn;
Michael Reed05e8ec12006-01-13 14:31:54 -0600944
945 /* don't know what to do as only one scsi (fc) host was allocated */
946 if (portnum != 0)
947 return;
948
Michael Reed5d947f22006-07-31 12:19:30 -0500949 pp0 = &ioc->fc_port_page0[portnum];
950 sh = ioc->sh;
951
952 sn = fc_host_symbolic_name(sh);
953 snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",
954 ioc->prod_name,
955 MPT_FW_REV_MAGIC_ID_STRING,
956 ioc->facts.FWVersion.Word);
957
958 fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;
959
960 fc_host_maxframe_size(sh) = pp0->MaxFrameSize;
961
962 fc_host_node_name(sh) =
963 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
964
965 fc_host_port_name(sh) =
966 (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;
967
968 fc_host_port_id(sh) = pp0->PortIdentifier;
969
970 class = pp0->SupportedServiceClass;
Michael Reed05e8ec12006-01-13 14:31:54 -0600971 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
972 cos |= FC_COS_CLASS1;
973 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
974 cos |= FC_COS_CLASS2;
975 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
976 cos |= FC_COS_CLASS3;
Michael Reed5d947f22006-07-31 12:19:30 -0500977 fc_host_supported_classes(sh) = cos;
Michael Reed05e8ec12006-01-13 14:31:54 -0600978
Michael Reed5d947f22006-07-31 12:19:30 -0500979 if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)
980 speed = FC_PORTSPEED_1GBIT;
981 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)
982 speed = FC_PORTSPEED_2GBIT;
983 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)
984 speed = FC_PORTSPEED_4GBIT;
985 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)
986 speed = FC_PORTSPEED_10GBIT;
987 else
988 speed = FC_PORTSPEED_UNKNOWN;
989 fc_host_speed(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -0600990
Michael Reed5d947f22006-07-31 12:19:30 -0500991 speed = 0;
992 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)
993 speed |= FC_PORTSPEED_1GBIT;
994 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
995 speed |= FC_PORTSPEED_2GBIT;
996 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
997 speed |= FC_PORTSPEED_4GBIT;
998 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
999 speed |= FC_PORTSPEED_10GBIT;
1000 fc_host_supported_speeds(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -06001001
Michael Reed5d947f22006-07-31 12:19:30 -05001002 port_state = FC_PORTSTATE_UNKNOWN;
1003 if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)
1004 port_state = FC_PORTSTATE_ONLINE;
1005 else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)
1006 port_state = FC_PORTSTATE_LINKDOWN;
1007 fc_host_port_state(sh) = port_state;
Michael Reed05e8ec12006-01-13 14:31:54 -06001008
Michael Reed5d947f22006-07-31 12:19:30 -05001009 port_type = FC_PORTTYPE_UNKNOWN;
1010 if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)
1011 port_type = FC_PORTTYPE_PTP;
1012 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)
1013 port_type = FC_PORTTYPE_LPORT;
1014 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)
1015 port_type = FC_PORTTYPE_NLPORT;
1016 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)
1017 port_type = FC_PORTTYPE_NPORT;
1018 fc_host_port_type(sh) = port_type;
Michael Reed05e8ec12006-01-13 14:31:54 -06001019
Michael Reed5d947f22006-07-31 12:19:30 -05001020 fc_host_fabric_name(sh) =
1021 (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?
1022 (u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :
1023 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
1024
Michael Reed05e8ec12006-01-13 14:31:54 -06001025}
1026
1027static void
David Howellsc4028952006-11-22 14:57:56 +00001028mptfc_setup_reset(struct work_struct *work)
Michael Reed419835e2006-05-24 15:07:40 -05001029{
David Howellsc4028952006-11-22 14:57:56 +00001030 MPT_ADAPTER *ioc =
1031 container_of(work, MPT_ADAPTER, fc_setup_reset_work);
Michael Reed419835e2006-05-24 15:07:40 -05001032 u64 pn;
1033 struct mptfc_rport_info *ri;
1034
1035 /* reset about to happen, delete (block) all rports */
1036 list_for_each_entry(ri, &ioc->fc_rports, list) {
1037 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1038 ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
1039 fc_remote_port_delete(ri->rport); /* won't sleep */
1040 ri->rport = NULL;
1041
1042 pn = (u64)ri->pg0.WWPN.High << 32 |
1043 (u64)ri->pg0.WWPN.Low;
1044 dfcprintk ((MYIOC_s_INFO_FMT
1045 "mptfc_setup_reset.%d: %llx deleted\n",
1046 ioc->name,
1047 ioc->sh->host_no,
1048 (unsigned long long)pn));
1049 }
1050 }
1051}
1052
1053static void
David Howellsc4028952006-11-22 14:57:56 +00001054mptfc_rescan_devices(struct work_struct *work)
Michael Reed05e8ec12006-01-13 14:31:54 -06001055{
David Howellsc4028952006-11-22 14:57:56 +00001056 MPT_ADAPTER *ioc =
1057 container_of(work, MPT_ADAPTER, fc_rescan_work);
Michael Reed05e8ec12006-01-13 14:31:54 -06001058 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001059 u64 pn;
Michael Reed05e8ec12006-01-13 14:31:54 -06001060 struct mptfc_rport_info *ri;
1061
Michael Reed3a0c56d2006-07-31 12:19:50 -05001062 /* start by tagging all ports as missing */
1063 list_for_each_entry(ri, &ioc->fc_rports, list) {
1064 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1065 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
Michael Reed05e8ec12006-01-13 14:31:54 -06001066 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001067 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001068
Michael Reed3a0c56d2006-07-31 12:19:50 -05001069 /*
1070 * now rescan devices known to adapter,
1071 * will reregister existing rports
1072 */
1073 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1074 (void) mptfc_GetFcPortPage0(ioc, ii);
1075 mptfc_init_host_attr(ioc, ii); /* refresh */
1076 mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev);
1077 }
1078
1079 /* delete devices still missing */
1080 list_for_each_entry(ri, &ioc->fc_rports, list) {
1081 /* if newly missing, delete it */
1082 if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
1083
1084 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
1085 MPT_RPORT_INFO_FLAGS_MISSING);
1086 fc_remote_port_delete(ri->rport); /* won't sleep */
1087 ri->rport = NULL;
1088
1089 pn = (u64)ri->pg0.WWPN.High << 32 |
1090 (u64)ri->pg0.WWPN.Low;
1091 dfcprintk ((MYIOC_s_INFO_FMT
1092 "mptfc_rescan.%d: %llx deleted\n",
1093 ioc->name,
1094 ioc->sh->host_no,
1095 (unsigned long long)pn));
Michael Reed05e8ec12006-01-13 14:31:54 -06001096 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001097 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001098}
1099
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001100static int
1101mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1102{
1103 struct Scsi_Host *sh;
1104 MPT_SCSI_HOST *hd;
1105 MPT_ADAPTER *ioc;
1106 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001107 int ii;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001108 int numSGE = 0;
1109 int scale;
1110 int ioc_cap;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001111 int error=0;
1112 int r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001113
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001114 if ((r = mpt_attach(pdev,id)) != 0)
1115 return r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001116
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001117 ioc = pci_get_drvdata(pdev);
Moore, Eric Dean d335cc32005-04-30 17:09:38 -05001118 ioc->DoneCtx = mptfcDoneCtx;
1119 ioc->TaskCtx = mptfcTaskCtx;
1120 ioc->InternalCtx = mptfcInternalCtx;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001121
1122 /* Added sanity check on readiness of the MPT adapter.
1123 */
1124 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1125 printk(MYIOC_s_WARN_FMT
1126 "Skipping because it's not operational!\n",
1127 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001128 error = -ENODEV;
1129 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001130 }
1131
1132 if (!ioc->active) {
1133 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1134 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001135 error = -ENODEV;
1136 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001137 }
1138
1139 /* Sanity check - ensure at least 1 port is INITIATOR capable
1140 */
1141 ioc_cap = 0;
1142 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1143 if (ioc->pfacts[ii].ProtocolFlags &
1144 MPI_PORTFACTS_PROTOCOL_INITIATOR)
1145 ioc_cap ++;
1146 }
1147
1148 if (!ioc_cap) {
1149 printk(MYIOC_s_WARN_FMT
1150 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1151 ioc->name, ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001152 return 0;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001153 }
1154
1155 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
1156
1157 if (!sh) {
1158 printk(MYIOC_s_WARN_FMT
1159 "Unable to register controller with SCSI subsystem\n",
1160 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001161 error = -1;
1162 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001163 }
1164
Michael Reed80d3ac72006-05-24 15:07:09 -05001165 spin_lock_init(&ioc->fc_rescan_work_lock);
David Howellsc4028952006-11-22 14:57:56 +00001166 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
1167 INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
Michael Reed05e8ec12006-01-13 14:31:54 -06001168
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001169 spin_lock_irqsave(&ioc->FreeQlock, flags);
1170
1171 /* Attach the SCSI Host to the IOC structure
1172 */
1173 ioc->sh = sh;
1174
1175 sh->io_port = 0;
1176 sh->n_io_port = 0;
1177 sh->irq = 0;
1178
1179 /* set 16 byte cdb's */
1180 sh->max_cmd_len = 16;
1181
Eric Moore793955f2007-01-29 09:42:20 -07001182 sh->max_id = ioc->pfacts->MaxDevices;
1183 sh->max_lun = max_lun;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001184
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001185 sh->this_id = ioc->pfacts[0].PortSCSIID;
1186
1187 /* Required entry.
1188 */
1189 sh->unique_id = ioc->id;
1190
1191 /* Verify that we won't exceed the maximum
1192 * number of chain buffers
1193 * We can optimize: ZZ = req_sz/sizeof(SGE)
1194 * For 32bit SGE's:
1195 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1196 * + (req_sz - 64)/sizeof(SGE)
1197 * A slightly different algorithm is required for
1198 * 64bit SGEs.
1199 */
1200 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
1201 if (sizeof(dma_addr_t) == sizeof(u64)) {
1202 numSGE = (scale - 1) *
1203 (ioc->facts.MaxChainDepth-1) + scale +
1204 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
1205 sizeof(u32));
1206 } else {
1207 numSGE = 1 + (scale - 1) *
1208 (ioc->facts.MaxChainDepth-1) + scale +
1209 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
1210 sizeof(u32));
1211 }
1212
1213 if (numSGE < sh->sg_tablesize) {
1214 /* Reset this value */
1215 dprintk((MYIOC_s_INFO_FMT
1216 "Resetting sg_tablesize to %d from %d\n",
1217 ioc->name, numSGE, sh->sg_tablesize));
1218 sh->sg_tablesize = numSGE;
1219 }
1220
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001221 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1222
1223 hd = (MPT_SCSI_HOST *) sh->hostdata;
1224 hd->ioc = ioc;
1225
1226 /* SCSI needs scsi_cmnd lookup table!
1227 * (with size equal to req_depth*PtrSz!)
1228 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001229 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
1230 if (!hd->ScsiLookup) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001231 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001232 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001233 }
1234
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001235 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
1236 ioc->name, hd->ScsiLookup));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001237
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001238 /* Clear the TM flags
1239 */
1240 hd->tmPending = 0;
1241 hd->tmState = TM_STATE_NONE;
1242 hd->resetPending = 0;
1243 hd->abortSCpnt = NULL;
1244
1245 /* Clear the pointer used to store
1246 * single-threaded commands, i.e., those
1247 * issued during a bus scan, dv and
1248 * configuration pages.
1249 */
1250 hd->cmdPtr = NULL;
1251
1252 /* Initialize this SCSI Hosts' timers
1253 * To use, set the timer expires field
1254 * and add_timer
1255 */
1256 init_timer(&hd->timer);
1257 hd->timer.data = (unsigned long) hd;
1258 hd->timer.function = mptscsih_timer_expired;
1259
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001260 init_waitqueue_head(&hd->scandv_waitq);
1261 hd->scandv_wait_done = 0;
1262 hd->last_queue_full = 0;
1263
Michael Reed05e8ec12006-01-13 14:31:54 -06001264 sh->transportt = mptfc_transport_template;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001265 error = scsi_add_host (sh, &ioc->pcidev->dev);
1266 if(error) {
1267 dprintk((KERN_ERR MYNAM
1268 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001269 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001270 }
1271
Moore, Eric65207fe2006-04-21 16:14:35 -06001272 /* initialize workqueue */
1273
1274 snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d",
1275 sh->host_no);
1276 ioc->fc_rescan_work_q =
1277 create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
1278 if (!ioc->fc_rescan_work_q)
1279 goto out_mptfc_probe;
1280
1281 /*
Michael Reed80d3ac72006-05-24 15:07:09 -05001282 * Pre-fetch FC port WWN and stuff...
1283 * (FCPortPage0_t stuff)
1284 */
1285 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1286 (void) mptfc_GetFcPortPage0(ioc, ii);
1287 }
Michael Reedca2f9382006-05-24 15:07:24 -05001288 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001289
1290 /*
Moore, Eric65207fe2006-04-21 16:14:35 -06001291 * scan for rports -
1292 * by doing it via the workqueue, some locking is eliminated
1293 */
1294
Moore, Eric65207fe2006-04-21 16:14:35 -06001295 queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
1296 flush_workqueue(ioc->fc_rescan_work_q);
Michael Reed05e8ec12006-01-13 14:31:54 -06001297
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001298 return 0;
1299
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001300out_mptfc_probe:
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001301
1302 mptscsih_remove(pdev);
1303 return error;
1304}
1305
1306static struct pci_driver mptfc_driver = {
1307 .name = "mptfc",
1308 .id_table = mptfc_pci_table,
1309 .probe = mptfc_probe,
Michael Reed05e8ec12006-01-13 14:31:54 -06001310 .remove = __devexit_p(mptfc_remove),
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001311 .shutdown = mptscsih_shutdown,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001312#ifdef CONFIG_PM
1313 .suspend = mptscsih_suspend,
1314 .resume = mptscsih_resume,
1315#endif
1316};
1317
Michael Reed80d3ac72006-05-24 15:07:09 -05001318static int
1319mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1320{
1321 MPT_SCSI_HOST *hd;
1322 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1323 unsigned long flags;
1324 int rc=1;
1325
1326 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
1327 ioc->name, event));
1328
1329 if (ioc->sh == NULL ||
1330 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
1331 return 1;
1332
1333 switch (event) {
1334 case MPI_EVENT_RESCAN:
1335 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1336 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001337 queue_work(ioc->fc_rescan_work_q,
1338 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001339 }
1340 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1341 break;
1342 default:
1343 rc = mptscsih_event_process(ioc,pEvReply);
1344 break;
1345 }
1346 return rc;
1347}
1348
1349static int
1350mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1351{
1352 int rc;
1353 unsigned long flags;
1354
1355 rc = mptscsih_ioc_reset(ioc,reset_phase);
1356 if (rc == 0)
1357 return rc;
1358
1359
1360 dtmprintk((KERN_WARNING MYNAM
1361 ": IOC %s_reset routed to FC host driver!\n",
1362 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
1363 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
1364
1365 if (reset_phase == MPT_IOC_SETUP_RESET) {
Michael Reed419835e2006-05-24 15:07:40 -05001366 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1367 if (ioc->fc_rescan_work_q) {
1368 queue_work(ioc->fc_rescan_work_q,
1369 &ioc->fc_setup_reset_work);
1370 }
1371 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
Michael Reed80d3ac72006-05-24 15:07:09 -05001372 }
1373
1374 else if (reset_phase == MPT_IOC_PRE_RESET) {
1375 }
1376
1377 else { /* MPT_IOC_POST_RESET */
Michael Reedca2f9382006-05-24 15:07:24 -05001378 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001379 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1380 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001381 queue_work(ioc->fc_rescan_work_q,
1382 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001383 }
1384 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1385 }
1386 return 1;
1387}
1388
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001389/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1390/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001391 * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001392 *
1393 * Returns 0 for success, non-zero for failure.
1394 */
1395static int __init
1396mptfc_init(void)
1397{
Michael Reed05e8ec12006-01-13 14:31:54 -06001398 int error;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001399
1400 show_mptmod_ver(my_NAME, my_VERSION);
1401
Michael Reedca2f9382006-05-24 15:07:24 -05001402 /* sanity check module parameters */
1403 if (mptfc_dev_loss_tmo <= 0)
Michael Reed05e8ec12006-01-13 14:31:54 -06001404 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
1405
1406 mptfc_transport_template =
1407 fc_attach_transport(&mptfc_transport_functions);
1408
1409 if (!mptfc_transport_template)
1410 return -ENODEV;
1411
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001412 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
1413 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
1414 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
1415
Michael Reed80d3ac72006-05-24 15:07:09 -05001416 if (mpt_event_register(mptfcDoneCtx, mptfc_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07001417 devtverboseprintk((KERN_INFO MYNAM
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001418 ": Registered for IOC event notifications\n"));
1419 }
1420
Michael Reed80d3ac72006-05-24 15:07:09 -05001421 if (mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset) == 0) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001422 dprintk((KERN_INFO MYNAM
1423 ": Registered for IOC reset notifications\n"));
1424 }
1425
Michael Reed05e8ec12006-01-13 14:31:54 -06001426 error = pci_register_driver(&mptfc_driver);
Michael Reed3bc7bf12006-01-25 18:05:18 -07001427 if (error)
Michael Reed05e8ec12006-01-13 14:31:54 -06001428 fc_release_transport(mptfc_transport_template);
Michael Reed05e8ec12006-01-13 14:31:54 -06001429
1430 return error;
1431}
1432
1433/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1434/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001435 * mptfc_remove - Remove fc infrastructure for devices
Michael Reed05e8ec12006-01-13 14:31:54 -06001436 * @pdev: Pointer to pci_dev structure
1437 *
1438 */
Michael Reed3bc7bf12006-01-25 18:05:18 -07001439static void __devexit
1440mptfc_remove(struct pci_dev *pdev)
Michael Reed05e8ec12006-01-13 14:31:54 -06001441{
Moore, Eric65207fe2006-04-21 16:14:35 -06001442 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1443 struct mptfc_rport_info *p, *n;
1444 struct workqueue_struct *work_q;
1445 unsigned long flags;
Michael Reedca2f9382006-05-24 15:07:24 -05001446 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001447
1448 /* destroy workqueue */
1449 if ((work_q=ioc->fc_rescan_work_q)) {
1450 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1451 ioc->fc_rescan_work_q = NULL;
1452 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1453 destroy_workqueue(work_q);
1454 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001455
1456 fc_remove_host(ioc->sh);
1457
1458 list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
1459 list_del(&p->list);
1460 kfree(p);
1461 }
1462
Michael Reedca2f9382006-05-24 15:07:24 -05001463 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
1464 if (ioc->fc_data.fc_port_page1[ii].data) {
1465 pci_free_consistent(ioc->pcidev,
1466 ioc->fc_data.fc_port_page1[ii].pg_sz,
1467 (u8 *) ioc->fc_data.fc_port_page1[ii].data,
1468 ioc->fc_data.fc_port_page1[ii].dma);
1469 ioc->fc_data.fc_port_page1[ii].data = NULL;
1470 }
1471 }
1472
Michael Reed05e8ec12006-01-13 14:31:54 -06001473 mptscsih_remove(pdev);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001474}
1475
1476/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1477/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1478/**
1479 * mptfc_exit - Unregisters MPT adapter(s)
1480 *
1481 */
1482static void __exit
1483mptfc_exit(void)
1484{
1485 pci_unregister_driver(&mptfc_driver);
Michael Reed05e8ec12006-01-13 14:31:54 -06001486 fc_release_transport(mptfc_transport_template);
1487
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001488 mpt_reset_deregister(mptfcDoneCtx);
1489 dprintk((KERN_INFO MYNAM
1490 ": Deregistered for IOC reset notifications\n"));
1491
1492 mpt_event_deregister(mptfcDoneCtx);
1493 dprintk((KERN_INFO MYNAM
1494 ": Deregistered for IOC event notifications\n"));
1495
1496 mpt_deregister(mptfcInternalCtx);
1497 mpt_deregister(mptfcTaskCtx);
1498 mpt_deregister(mptfcDoneCtx);
1499}
1500
1501module_init(mptfc_init);
1502module_exit(mptfc_exit);