blob: b766445f19aa30050fa60b18d502d1bb0a6ab5e3 [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,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400133};
134
135/****************************************************************************
136 * Supported hardware
137 */
138
139static struct pci_device_id mptfc_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -0600140 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC909,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400141 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600142 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400143 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600144 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400145 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600146 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919X,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400147 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600148 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929X,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400149 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600150 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC939X,
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600151 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600152 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949X,
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600153 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600154 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E,
Moore, Eric6d5b0c32006-01-13 16:25:26 -0700155 PCI_ANY_ID, PCI_ANY_ID },
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400156 {0} /* Terminating entry */
157};
158MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
159
Michael Reed05e8ec12006-01-13 14:31:54 -0600160static struct scsi_transport_template *mptfc_transport_template = NULL;
161
Adrian Bunk03fbcbc2006-01-25 02:00:52 +0100162static struct fc_function_template mptfc_transport_functions = {
Michael Reed05e8ec12006-01-13 14:31:54 -0600163 .dd_fcrport_size = 8,
164 .show_host_node_name = 1,
165 .show_host_port_name = 1,
166 .show_host_supported_classes = 1,
167 .show_host_port_id = 1,
168 .show_rport_supported_classes = 1,
169 .show_starget_node_name = 1,
170 .show_starget_port_name = 1,
171 .show_starget_port_id = 1,
172 .set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
173 .show_rport_dev_loss_tmo = 1,
Michael Reed5d947f22006-07-31 12:19:30 -0500174 .show_host_supported_speeds = 1,
175 .show_host_maxframe_size = 1,
176 .show_host_speed = 1,
177 .show_host_fabric_name = 1,
178 .show_host_port_type = 1,
179 .show_host_port_state = 1,
180 .show_host_symbolic_name = 1,
Michael Reed05e8ec12006-01-13 14:31:54 -0600181};
182
Michael Reed35508e42006-10-06 15:39:25 -0500183static int
184mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
185 int (*func)(struct scsi_cmnd *SCpnt),
186 const char *caller)
187{
188 struct scsi_device *sdev = SCpnt->device;
189 struct Scsi_Host *shost = sdev->host;
190 struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
191 unsigned long flags;
192 int ready;
193
194 spin_lock_irqsave(shost->host_lock, flags);
195 while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
196 spin_unlock_irqrestore(shost->host_lock, flags);
197 dfcprintk ((MYIOC_s_INFO_FMT
198 "mptfc_block_error_handler.%d: %d:%d, port status is "
199 "DID_IMM_RETRY, deferring %s recovery.\n",
200 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
201 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
202 SCpnt->device->id,SCpnt->device->lun,caller));
203 msleep(1000);
204 spin_lock_irqsave(shost->host_lock, flags);
205 }
206 spin_unlock_irqrestore(shost->host_lock, flags);
207
208 if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
209 dfcprintk ((MYIOC_s_INFO_FMT
210 "%s.%d: %d:%d, failing recovery, "
211 "port state %d, vdev %p.\n", caller,
212 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
213 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
214 SCpnt->device->id,SCpnt->device->lun,ready,
215 SCpnt->device->hostdata));
216 return FAILED;
217 }
218 dfcprintk ((MYIOC_s_INFO_FMT
219 "%s.%d: %d:%d, executing recovery.\n", caller,
220 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
221 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
222 SCpnt->device->id,SCpnt->device->lun));
223 return (*func)(SCpnt);
224}
225
226static int
227mptfc_abort(struct scsi_cmnd *SCpnt)
228{
229 return
230 mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
231}
232
233static int
234mptfc_dev_reset(struct scsi_cmnd *SCpnt)
235{
236 return
237 mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
238}
239
240static int
241mptfc_bus_reset(struct scsi_cmnd *SCpnt)
242{
243 return
244 mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
245}
246
247static int
248mptfc_host_reset(struct scsi_cmnd *SCpnt)
249{
250 return
251 mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
252}
253
Michael Reed05e8ec12006-01-13 14:31:54 -0600254static void
255mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
256{
257 if (timeout > 0)
258 rport->dev_loss_tmo = timeout;
259 else
260 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
261}
262
263static int
264mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
265{
266 FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
267 FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
268
269 if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
270 if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
271 return 0;
272 if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
273 return -1;
274 return 1;
275 }
276 if ((*aa)->CurrentBus < (*bb)->CurrentBus)
277 return -1;
278 return 1;
279}
280
281static int
282mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
283 void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
284{
285 ConfigPageHeader_t hdr;
286 CONFIGPARMS cfg;
287 FCDevicePage0_t *ppage0_alloc, *fc;
288 dma_addr_t page0_dma;
289 int data_sz;
290 int ii;
291
292 FCDevicePage0_t *p0_array=NULL, *p_p0;
293 FCDevicePage0_t **pp0_array=NULL, **p_pp0;
294
295 int rc = -ENOMEM;
296 U32 port_id = 0xffffff;
297 int num_targ = 0;
298 int max_bus = ioc->facts.MaxBuses;
Eric Moore793955f2007-01-29 09:42:20 -0700299 int max_targ;
Michael Reed05e8ec12006-01-13 14:31:54 -0600300
Eric Moore793955f2007-01-29 09:42:20 -0700301 max_targ = (ioc->facts.MaxDevices == 0) ? 256 : ioc->facts.MaxDevices;
Michael Reed05e8ec12006-01-13 14:31:54 -0600302
303 data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
304 p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL);
305 if (!p0_array)
306 goto out;
307
308 data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
309 p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
310 if (!pp0_array)
311 goto out;
312
313 do {
314 /* Get FC Device Page 0 header */
315 hdr.PageVersion = 0;
316 hdr.PageLength = 0;
317 hdr.PageNumber = 0;
318 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
319 cfg.cfghdr.hdr = &hdr;
320 cfg.physAddr = -1;
321 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
322 cfg.dir = 0;
323 cfg.pageAddr = port_id;
324 cfg.timeout = 0;
325
326 if ((rc = mpt_config(ioc, &cfg)) != 0)
327 break;
328
329 if (hdr.PageLength <= 0)
330 break;
331
332 data_sz = hdr.PageLength * 4;
333 ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
334 &page0_dma);
335 rc = -ENOMEM;
336 if (!ppage0_alloc)
337 break;
338
339 cfg.physAddr = page0_dma;
340 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
341
342 if ((rc = mpt_config(ioc, &cfg)) == 0) {
343 ppage0_alloc->PortIdentifier =
344 le32_to_cpu(ppage0_alloc->PortIdentifier);
345
346 ppage0_alloc->WWNN.Low =
347 le32_to_cpu(ppage0_alloc->WWNN.Low);
348
349 ppage0_alloc->WWNN.High =
350 le32_to_cpu(ppage0_alloc->WWNN.High);
351
352 ppage0_alloc->WWPN.Low =
353 le32_to_cpu(ppage0_alloc->WWPN.Low);
354
355 ppage0_alloc->WWPN.High =
356 le32_to_cpu(ppage0_alloc->WWPN.High);
357
358 ppage0_alloc->BBCredit =
359 le16_to_cpu(ppage0_alloc->BBCredit);
360
361 ppage0_alloc->MaxRxFrameSize =
362 le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
363
364 port_id = ppage0_alloc->PortIdentifier;
365 num_targ++;
366 *p_p0 = *ppage0_alloc; /* save data */
367 *p_pp0++ = p_p0++; /* save addr */
368 }
369 pci_free_consistent(ioc->pcidev, data_sz,
370 (u8 *) ppage0_alloc, page0_dma);
371 if (rc != 0)
372 break;
373
374 } while (port_id <= 0xff0000);
375
376 if (num_targ) {
377 /* sort array */
378 if (num_targ > 1)
379 sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
380 mptfc_FcDevPage0_cmp_func, NULL);
381 /* call caller's func for each targ */
382 for (ii = 0; ii < num_targ; ii++) {
383 fc = *(pp0_array+ii);
384 func(ioc, ioc_port, fc);
385 }
386 }
387
388 out:
Jesper Juhl8f760782006-06-27 02:55:06 -0700389 kfree(pp0_array);
390 kfree(p0_array);
Michael Reed05e8ec12006-01-13 14:31:54 -0600391 return rc;
392}
393
394static int
395mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
396{
397 /* not currently usable */
398 if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
399 MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
400 return -1;
401
402 if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
403 return -1;
404
405 if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
406 return -1;
407
408 /*
409 * board data structure already normalized to platform endianness
410 * shifted to avoid unaligned access on 64 bit architecture
411 */
412 rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
413 rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
414 rid->port_id = pg0->PortIdentifier;
415 rid->roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600416
417 return 0;
418}
419
420static void
421mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
422{
423 struct fc_rport_identifiers rport_ids;
424 struct fc_rport *rport;
425 struct mptfc_rport_info *ri;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700426 int new_ri = 1;
Moore, Eric65207fe2006-04-21 16:14:35 -0600427 u64 pn, nn;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700428 VirtTarget *vtarget;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500429 u32 roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600430
431 if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
432 return;
433
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500434 roles |= FC_RPORT_ROLE_FCP_TARGET;
435 if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
436 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
437
Michael Reed05e8ec12006-01-13 14:31:54 -0600438 /* scan list looking for a match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600439 list_for_each_entry(ri, &ioc->fc_rports, list) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700440 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
441 if (pn == rport_ids.port_name) { /* match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600442 list_move_tail(&ri->list, &ioc->fc_rports);
Michael Reed3bc7bf12006-01-25 18:05:18 -0700443 new_ri = 0;
Michael Reed05e8ec12006-01-13 14:31:54 -0600444 break;
445 }
446 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700447 if (new_ri) { /* allocate one */
Michael Reed05e8ec12006-01-13 14:31:54 -0600448 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
449 if (!ri)
450 return;
Michael Reed05e8ec12006-01-13 14:31:54 -0600451 list_add_tail(&ri->list, &ioc->fc_rports);
452 }
453
454 ri->pg0 = *pg0; /* add/update pg0 data */
455 ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
456
Michael Reed3bc7bf12006-01-25 18:05:18 -0700457 /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
Michael Reed05e8ec12006-01-13 14:31:54 -0600458 if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
459 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700460 rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
Michael Reed05e8ec12006-01-13 14:31:54 -0600461 if (rport) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700462 ri->rport = rport;
463 if (new_ri) /* may have been reset by user */
464 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
Michael Reed05e8ec12006-01-13 14:31:54 -0600465 /*
466 * if already mapped, remap here. If not mapped,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700467 * target_alloc will allocate vtarget and map,
468 * slave_alloc will fill in vdev from vtarget.
Michael Reed05e8ec12006-01-13 14:31:54 -0600469 */
Michael Reed3bc7bf12006-01-25 18:05:18 -0700470 if (ri->starget) {
471 vtarget = ri->starget->hostdata;
472 if (vtarget) {
Eric Moore793955f2007-01-29 09:42:20 -0700473 vtarget->id = pg0->CurrentTargetID;
474 vtarget->channel = pg0->CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700475 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600476 }
Moore, Eric65207fe2006-04-21 16:14:35 -0600477 *((struct mptfc_rport_info **)rport->dd_data) = ri;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500478 /* scan will be scheduled once rport becomes a target */
479 fc_remote_port_rolechg(rport,roles);
Moore, Eric65207fe2006-04-21 16:14:35 -0600480
481 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
482 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700483 dfcprintk ((MYIOC_s_INFO_FMT
484 "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600485 "rport tid %d, tmo %d\n",
Michael Reed3bc7bf12006-01-25 18:05:18 -0700486 ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700487 ioc->sh->host_no,
Michael Reed05e8ec12006-01-13 14:31:54 -0600488 pg0->PortIdentifier,
Moore, Eric65207fe2006-04-21 16:14:35 -0600489 (unsigned long long)nn,
490 (unsigned long long)pn,
Michael Reed05e8ec12006-01-13 14:31:54 -0600491 pg0->CurrentTargetID,
492 ri->rport->scsi_target_id,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700493 ri->rport->dev_loss_tmo));
Michael Reed05e8ec12006-01-13 14:31:54 -0600494 } else {
495 list_del(&ri->list);
496 kfree(ri);
497 ri = NULL;
498 }
499 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600500}
501
502/*
Michael Reed3bc7bf12006-01-25 18:05:18 -0700503 * OS entry point to allow for host driver to free allocated memory
504 * Called if no device present or device being unloaded
505 */
506static void
507mptfc_target_destroy(struct scsi_target *starget)
508{
509 struct fc_rport *rport;
510 struct mptfc_rport_info *ri;
511
512 rport = starget_to_rport(starget);
513 if (rport) {
514 ri = *((struct mptfc_rport_info **)rport->dd_data);
515 if (ri) /* better be! */
516 ri->starget = NULL;
517 }
518 if (starget->hostdata)
519 kfree(starget->hostdata);
520 starget->hostdata = NULL;
521}
522
523/*
524 * OS entry point to allow host driver to alloc memory
525 * for each scsi target. Called once per device the bus scan.
526 * Return non-zero if allocation fails.
527 */
528static int
529mptfc_target_alloc(struct scsi_target *starget)
530{
531 VirtTarget *vtarget;
532 struct fc_rport *rport;
533 struct mptfc_rport_info *ri;
534 int rc;
535
536 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
537 if (!vtarget)
538 return -ENOMEM;
539 starget->hostdata = vtarget;
540
541 rc = -ENODEV;
542 rport = starget_to_rport(starget);
543 if (rport) {
544 ri = *((struct mptfc_rport_info **)rport->dd_data);
545 if (ri) { /* better be! */
Eric Moore793955f2007-01-29 09:42:20 -0700546 vtarget->id = ri->pg0.CurrentTargetID;
547 vtarget->channel = ri->pg0.CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700548 ri->starget = starget;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700549 rc = 0;
550 }
551 }
552 if (rc != 0) {
553 kfree(vtarget);
554 starget->hostdata = NULL;
555 }
556
557 return rc;
558}
559
560/*
Michael Reed05e8ec12006-01-13 14:31:54 -0600561 * OS entry point to allow host driver to alloc memory
562 * for each scsi device. Called once per device the bus scan.
563 * Return non-zero if allocation fails.
564 * Init memory once per LUN.
565 */
Adrian Bunk03fbcbc2006-01-25 02:00:52 +0100566static int
Michael Reed05e8ec12006-01-13 14:31:54 -0600567mptfc_slave_alloc(struct scsi_device *sdev)
568{
569 MPT_SCSI_HOST *hd;
570 VirtTarget *vtarget;
571 VirtDevice *vdev;
572 struct scsi_target *starget;
573 struct fc_rport *rport;
Michael Reed05e8ec12006-01-13 14:31:54 -0600574
575
Moore, Eric65207fe2006-04-21 16:14:35 -0600576 starget = scsi_target(sdev);
577 rport = starget_to_rport(starget);
Michael Reed05e8ec12006-01-13 14:31:54 -0600578
579 if (!rport || fc_remote_port_chkready(rport))
580 return -ENXIO;
581
582 hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
583
Michael Reed3bc7bf12006-01-25 18:05:18 -0700584 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Michael Reed05e8ec12006-01-13 14:31:54 -0600585 if (!vdev) {
586 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
587 hd->ioc->name, sizeof(VirtDevice));
588 return -ENOMEM;
589 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600590
Michael Reed05e8ec12006-01-13 14:31:54 -0600591
Michael Reed05e8ec12006-01-13 14:31:54 -0600592 sdev->hostdata = vdev;
Michael Reed05e8ec12006-01-13 14:31:54 -0600593 vtarget = starget->hostdata;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700594
Michael Reed05e8ec12006-01-13 14:31:54 -0600595 if (vtarget->num_luns == 0) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700596 vtarget->ioc_id = hd->ioc->id;
Eric Mooreba856d32006-07-11 17:34:01 -0600597 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
Michael Reed05e8ec12006-01-13 14:31:54 -0600598 }
599
Michael Reed05e8ec12006-01-13 14:31:54 -0600600 vdev->vtarget = vtarget;
Michael Reed05e8ec12006-01-13 14:31:54 -0600601 vdev->lun = sdev->lun;
Michael Reed05e8ec12006-01-13 14:31:54 -0600602
Michael Reed05e8ec12006-01-13 14:31:54 -0600603 vtarget->num_luns++;
604
Moore, Eric65207fe2006-04-21 16:14:35 -0600605
Moore, Eric914c2d82006-03-14 09:19:36 -0700606#ifdef DMPT_DEBUG_FC
Moore, Eric65207fe2006-04-21 16:14:35 -0600607 {
608 u64 nn, pn;
Moore, Eric914c2d82006-03-14 09:19:36 -0700609 struct mptfc_rport_info *ri;
610 ri = *((struct mptfc_rport_info **)rport->dd_data);
Moore, Eric65207fe2006-04-21 16:14:35 -0600611 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
612 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700613 dfcprintk ((MYIOC_s_INFO_FMT
614 "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600615 "CurrentTargetID %d, %x %llx %llx\n",
Moore, Eric914c2d82006-03-14 09:19:36 -0700616 hd->ioc->name,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700617 sdev->host->host_no,
618 vtarget->num_luns,
619 sdev->id, ri->pg0.CurrentTargetID,
Moore, Eric65207fe2006-04-21 16:14:35 -0600620 ri->pg0.PortIdentifier,
621 (unsigned long long)pn,
622 (unsigned long long)nn));
Moore, Eric914c2d82006-03-14 09:19:36 -0700623 }
624#endif
Michael Reed05e8ec12006-01-13 14:31:54 -0600625
626 return 0;
627}
628
629static int
630mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
631{
Michael Reed3bc7bf12006-01-25 18:05:18 -0700632 struct mptfc_rport_info *ri;
Michael Reed05e8ec12006-01-13 14:31:54 -0600633 struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
634 int err;
Eric Moore793955f2007-01-29 09:42:20 -0700635 VirtDevice *vdev = SCpnt->device->hostdata;
Michael Reed05e8ec12006-01-13 14:31:54 -0600636
Eric Moore793955f2007-01-29 09:42:20 -0700637 if (!vdev || !vdev->vtarget) {
638 SCpnt->result = DID_NO_CONNECT << 16;
Michael Reed05e8ec12006-01-13 14:31:54 -0600639 done(SCpnt);
640 return 0;
641 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700642
Eric Moore793955f2007-01-29 09:42:20 -0700643 err = fc_remote_port_chkready(rport);
644 if (unlikely(err)) {
645 SCpnt->result = err;
Michael Reed35508e42006-10-06 15:39:25 -0500646 done(SCpnt);
647 return 0;
648 }
649
Moore, Eric65207fe2006-04-21 16:14:35 -0600650 /* dd_data is null until finished adding target */
651 ri = *((struct mptfc_rport_info **)rport->dd_data);
652 if (unlikely(!ri)) {
653 dfcprintk ((MYIOC_s_INFO_FMT
654 "mptfc_qcmd.%d: %d:%d, dd_data is null.\n",
655 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
656 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
657 SCpnt->device->id,SCpnt->device->lun));
658 SCpnt->result = DID_IMM_RETRY << 16;
659 done(SCpnt);
660 return 0;
661 }
662
663 err = mptscsih_qcmd(SCpnt,done);
664#ifdef DMPT_DEBUG_FC
665 if (unlikely(err)) {
666 dfcprintk ((MYIOC_s_INFO_FMT
Michael Reed419835e2006-05-24 15:07:40 -0500667 "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero, (%x).\n",
Moore, Eric65207fe2006-04-21 16:14:35 -0600668 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
669 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
Michael Reed419835e2006-05-24 15:07:40 -0500670 SCpnt->device->id,SCpnt->device->lun,err));
Moore, Eric65207fe2006-04-21 16:14:35 -0600671 }
672#endif
673 return err;
Michael Reed05e8ec12006-01-13 14:31:54 -0600674}
675
Michael Reed80d3ac72006-05-24 15:07:09 -0500676/*
677 * mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
678 * @ioc: Pointer to MPT_ADAPTER structure
679 * @portnum: IOC Port number
680 *
681 * Return: 0 for success
682 * -ENOMEM if no memory available
683 * -EPERM if not allowed due to ISR context
684 * -EAGAIN if no msg frames currently available
685 * -EFAULT for non-successful reply or no reply (timeout)
686 * -EINVAL portnum arg out of range (hardwired to two elements)
687 */
688static int
689mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
690{
691 ConfigPageHeader_t hdr;
692 CONFIGPARMS cfg;
693 FCPortPage0_t *ppage0_alloc;
694 FCPortPage0_t *pp0dest;
695 dma_addr_t page0_dma;
696 int data_sz;
697 int copy_sz;
698 int rc;
699 int count = 400;
700
701 if (portnum > 1)
702 return -EINVAL;
703
704 /* Get FCPort Page 0 header */
705 hdr.PageVersion = 0;
706 hdr.PageLength = 0;
707 hdr.PageNumber = 0;
708 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
709 cfg.cfghdr.hdr = &hdr;
710 cfg.physAddr = -1;
711 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
712 cfg.dir = 0;
713 cfg.pageAddr = portnum;
714 cfg.timeout = 0;
715
716 if ((rc = mpt_config(ioc, &cfg)) != 0)
717 return rc;
718
719 if (hdr.PageLength == 0)
720 return 0;
721
722 data_sz = hdr.PageLength * 4;
723 rc = -ENOMEM;
724 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
725 if (ppage0_alloc) {
726
727 try_again:
728 memset((u8 *)ppage0_alloc, 0, data_sz);
729 cfg.physAddr = page0_dma;
730 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
731
732 if ((rc = mpt_config(ioc, &cfg)) == 0) {
733 /* save the data */
734 pp0dest = &ioc->fc_port_page0[portnum];
735 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
736 memcpy(pp0dest, ppage0_alloc, copy_sz);
737
738 /*
739 * Normalize endianness of structure data,
740 * by byte-swapping all > 1 byte fields!
741 */
742 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
743 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
744 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
745 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
746 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
747 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
748 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
749 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
750 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
751 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
752 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
753 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
754 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
755 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
756 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
757 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
758
759 /*
760 * if still doing discovery,
761 * hang loose a while until finished
762 */
Michael Reed77d88ee2006-07-31 12:19:40 -0500763 if ((pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) ||
764 (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE &&
765 (pp0dest->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK)
766 == MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT)) {
Michael Reed80d3ac72006-05-24 15:07:09 -0500767 if (count-- > 0) {
Michael Reedd6be06c2006-05-24 15:07:57 -0500768 msleep(100);
Michael Reed80d3ac72006-05-24 15:07:09 -0500769 goto try_again;
770 }
771 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
772 " complete.\n",
773 ioc->name);
774 }
775 }
776
777 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
778 }
779
780 return rc;
781}
782
Michael Reedca2f9382006-05-24 15:07:24 -0500783static int
784mptfc_WriteFcPortPage1(MPT_ADAPTER *ioc, int portnum)
785{
786 ConfigPageHeader_t hdr;
787 CONFIGPARMS cfg;
788 int rc;
789
790 if (portnum > 1)
791 return -EINVAL;
792
793 if (!(ioc->fc_data.fc_port_page1[portnum].data))
794 return -EINVAL;
795
796 /* get fcport page 1 header */
797 hdr.PageVersion = 0;
798 hdr.PageLength = 0;
799 hdr.PageNumber = 1;
800 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
801 cfg.cfghdr.hdr = &hdr;
802 cfg.physAddr = -1;
803 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
804 cfg.dir = 0;
805 cfg.pageAddr = portnum;
806 cfg.timeout = 0;
807
808 if ((rc = mpt_config(ioc, &cfg)) != 0)
809 return rc;
810
811 if (hdr.PageLength == 0)
812 return -ENODEV;
813
814 if (hdr.PageLength*4 != ioc->fc_data.fc_port_page1[portnum].pg_sz)
815 return -EINVAL;
816
817 cfg.physAddr = ioc->fc_data.fc_port_page1[portnum].dma;
818 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
819 cfg.dir = 1;
820
821 rc = mpt_config(ioc, &cfg);
822
823 return rc;
824}
825
826static int
827mptfc_GetFcPortPage1(MPT_ADAPTER *ioc, int portnum)
828{
829 ConfigPageHeader_t hdr;
830 CONFIGPARMS cfg;
831 FCPortPage1_t *page1_alloc;
832 dma_addr_t page1_dma;
833 int data_sz;
834 int rc;
835
836 if (portnum > 1)
837 return -EINVAL;
838
839 /* get fcport page 1 header */
840 hdr.PageVersion = 0;
841 hdr.PageLength = 0;
842 hdr.PageNumber = 1;
843 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
844 cfg.cfghdr.hdr = &hdr;
845 cfg.physAddr = -1;
846 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
847 cfg.dir = 0;
848 cfg.pageAddr = portnum;
849 cfg.timeout = 0;
850
851 if ((rc = mpt_config(ioc, &cfg)) != 0)
852 return rc;
853
854 if (hdr.PageLength == 0)
855 return -ENODEV;
856
857start_over:
858
859 if (ioc->fc_data.fc_port_page1[portnum].data == NULL) {
860 data_sz = hdr.PageLength * 4;
861 if (data_sz < sizeof(FCPortPage1_t))
862 data_sz = sizeof(FCPortPage1_t);
863
864 page1_alloc = (FCPortPage1_t *) pci_alloc_consistent(ioc->pcidev,
865 data_sz,
866 &page1_dma);
867 if (!page1_alloc)
868 return -ENOMEM;
869 }
870 else {
871 page1_alloc = ioc->fc_data.fc_port_page1[portnum].data;
872 page1_dma = ioc->fc_data.fc_port_page1[portnum].dma;
873 data_sz = ioc->fc_data.fc_port_page1[portnum].pg_sz;
874 if (hdr.PageLength * 4 > data_sz) {
875 ioc->fc_data.fc_port_page1[portnum].data = NULL;
876 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
877 page1_alloc, page1_dma);
878 goto start_over;
879 }
880 }
881
882 memset(page1_alloc,0,data_sz);
883
884 cfg.physAddr = page1_dma;
885 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
886
887 if ((rc = mpt_config(ioc, &cfg)) == 0) {
888 ioc->fc_data.fc_port_page1[portnum].data = page1_alloc;
889 ioc->fc_data.fc_port_page1[portnum].pg_sz = data_sz;
890 ioc->fc_data.fc_port_page1[portnum].dma = page1_dma;
891 }
892 else {
893 ioc->fc_data.fc_port_page1[portnum].data = NULL;
894 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
895 page1_alloc, page1_dma);
896 }
897
898 return rc;
899}
900
901static void
902mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
903{
904 int ii;
905 FCPortPage1_t *pp1;
906
907 #define MPTFC_FW_DEVICE_TIMEOUT (1)
908 #define MPTFC_FW_IO_PEND_TIMEOUT (1)
909 #define ON_FLAGS (MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY)
910 #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)
911
912 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
913 if (mptfc_GetFcPortPage1(ioc, ii) != 0)
914 continue;
915 pp1 = ioc->fc_data.fc_port_page1[ii].data;
916 if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)
917 && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)
918 && ((pp1->Flags & ON_FLAGS) == ON_FLAGS)
919 && ((pp1->Flags & OFF_FLAGS) == 0))
920 continue;
921 pp1->InitiatorDeviceTimeout = MPTFC_FW_DEVICE_TIMEOUT;
922 pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT;
923 pp1->Flags &= ~OFF_FLAGS;
924 pp1->Flags |= ON_FLAGS;
925 mptfc_WriteFcPortPage1(ioc, ii);
926 }
927}
928
929
Michael Reed05e8ec12006-01-13 14:31:54 -0600930static void
931mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
932{
Michael Reed5d947f22006-07-31 12:19:30 -0500933 unsigned class = 0;
934 unsigned cos = 0;
935 unsigned speed;
936 unsigned port_type;
937 unsigned port_state;
938 FCPortPage0_t *pp0;
939 struct Scsi_Host *sh;
940 char *sn;
Michael Reed05e8ec12006-01-13 14:31:54 -0600941
942 /* don't know what to do as only one scsi (fc) host was allocated */
943 if (portnum != 0)
944 return;
945
Michael Reed5d947f22006-07-31 12:19:30 -0500946 pp0 = &ioc->fc_port_page0[portnum];
947 sh = ioc->sh;
948
949 sn = fc_host_symbolic_name(sh);
950 snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",
951 ioc->prod_name,
952 MPT_FW_REV_MAGIC_ID_STRING,
953 ioc->facts.FWVersion.Word);
954
955 fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;
956
957 fc_host_maxframe_size(sh) = pp0->MaxFrameSize;
958
959 fc_host_node_name(sh) =
960 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
961
962 fc_host_port_name(sh) =
963 (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;
964
965 fc_host_port_id(sh) = pp0->PortIdentifier;
966
967 class = pp0->SupportedServiceClass;
Michael Reed05e8ec12006-01-13 14:31:54 -0600968 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
969 cos |= FC_COS_CLASS1;
970 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
971 cos |= FC_COS_CLASS2;
972 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
973 cos |= FC_COS_CLASS3;
Michael Reed5d947f22006-07-31 12:19:30 -0500974 fc_host_supported_classes(sh) = cos;
Michael Reed05e8ec12006-01-13 14:31:54 -0600975
Michael Reed5d947f22006-07-31 12:19:30 -0500976 if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)
977 speed = FC_PORTSPEED_1GBIT;
978 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)
979 speed = FC_PORTSPEED_2GBIT;
980 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)
981 speed = FC_PORTSPEED_4GBIT;
982 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)
983 speed = FC_PORTSPEED_10GBIT;
984 else
985 speed = FC_PORTSPEED_UNKNOWN;
986 fc_host_speed(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -0600987
Michael Reed5d947f22006-07-31 12:19:30 -0500988 speed = 0;
989 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)
990 speed |= FC_PORTSPEED_1GBIT;
991 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
992 speed |= FC_PORTSPEED_2GBIT;
993 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
994 speed |= FC_PORTSPEED_4GBIT;
995 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
996 speed |= FC_PORTSPEED_10GBIT;
997 fc_host_supported_speeds(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -0600998
Michael Reed5d947f22006-07-31 12:19:30 -0500999 port_state = FC_PORTSTATE_UNKNOWN;
1000 if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)
1001 port_state = FC_PORTSTATE_ONLINE;
1002 else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)
1003 port_state = FC_PORTSTATE_LINKDOWN;
1004 fc_host_port_state(sh) = port_state;
Michael Reed05e8ec12006-01-13 14:31:54 -06001005
Michael Reed5d947f22006-07-31 12:19:30 -05001006 port_type = FC_PORTTYPE_UNKNOWN;
1007 if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)
1008 port_type = FC_PORTTYPE_PTP;
1009 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)
1010 port_type = FC_PORTTYPE_LPORT;
1011 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)
1012 port_type = FC_PORTTYPE_NLPORT;
1013 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)
1014 port_type = FC_PORTTYPE_NPORT;
1015 fc_host_port_type(sh) = port_type;
Michael Reed05e8ec12006-01-13 14:31:54 -06001016
Michael Reed5d947f22006-07-31 12:19:30 -05001017 fc_host_fabric_name(sh) =
1018 (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?
1019 (u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :
1020 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
1021
Michael Reed05e8ec12006-01-13 14:31:54 -06001022}
1023
1024static void
David Howellsc4028952006-11-22 14:57:56 +00001025mptfc_setup_reset(struct work_struct *work)
Michael Reed419835e2006-05-24 15:07:40 -05001026{
David Howellsc4028952006-11-22 14:57:56 +00001027 MPT_ADAPTER *ioc =
1028 container_of(work, MPT_ADAPTER, fc_setup_reset_work);
Michael Reed419835e2006-05-24 15:07:40 -05001029 u64 pn;
1030 struct mptfc_rport_info *ri;
1031
1032 /* reset about to happen, delete (block) all rports */
1033 list_for_each_entry(ri, &ioc->fc_rports, list) {
1034 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1035 ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
1036 fc_remote_port_delete(ri->rport); /* won't sleep */
1037 ri->rport = NULL;
1038
1039 pn = (u64)ri->pg0.WWPN.High << 32 |
1040 (u64)ri->pg0.WWPN.Low;
1041 dfcprintk ((MYIOC_s_INFO_FMT
1042 "mptfc_setup_reset.%d: %llx deleted\n",
1043 ioc->name,
1044 ioc->sh->host_no,
1045 (unsigned long long)pn));
1046 }
1047 }
1048}
1049
1050static void
David Howellsc4028952006-11-22 14:57:56 +00001051mptfc_rescan_devices(struct work_struct *work)
Michael Reed05e8ec12006-01-13 14:31:54 -06001052{
David Howellsc4028952006-11-22 14:57:56 +00001053 MPT_ADAPTER *ioc =
1054 container_of(work, MPT_ADAPTER, fc_rescan_work);
Michael Reed05e8ec12006-01-13 14:31:54 -06001055 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001056 u64 pn;
Michael Reed05e8ec12006-01-13 14:31:54 -06001057 struct mptfc_rport_info *ri;
1058
Michael Reed3a0c56d2006-07-31 12:19:50 -05001059 /* start by tagging all ports as missing */
1060 list_for_each_entry(ri, &ioc->fc_rports, list) {
1061 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1062 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
Michael Reed05e8ec12006-01-13 14:31:54 -06001063 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001064 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001065
Michael Reed3a0c56d2006-07-31 12:19:50 -05001066 /*
1067 * now rescan devices known to adapter,
1068 * will reregister existing rports
1069 */
1070 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1071 (void) mptfc_GetFcPortPage0(ioc, ii);
1072 mptfc_init_host_attr(ioc, ii); /* refresh */
1073 mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev);
1074 }
1075
1076 /* delete devices still missing */
1077 list_for_each_entry(ri, &ioc->fc_rports, list) {
1078 /* if newly missing, delete it */
1079 if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
1080
1081 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
1082 MPT_RPORT_INFO_FLAGS_MISSING);
1083 fc_remote_port_delete(ri->rport); /* won't sleep */
1084 ri->rport = NULL;
1085
1086 pn = (u64)ri->pg0.WWPN.High << 32 |
1087 (u64)ri->pg0.WWPN.Low;
1088 dfcprintk ((MYIOC_s_INFO_FMT
1089 "mptfc_rescan.%d: %llx deleted\n",
1090 ioc->name,
1091 ioc->sh->host_no,
1092 (unsigned long long)pn));
Michael Reed05e8ec12006-01-13 14:31:54 -06001093 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001094 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001095}
1096
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001097static int
1098mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1099{
1100 struct Scsi_Host *sh;
1101 MPT_SCSI_HOST *hd;
1102 MPT_ADAPTER *ioc;
1103 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001104 int ii;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001105 int numSGE = 0;
1106 int scale;
1107 int ioc_cap;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001108 int error=0;
1109 int r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001110
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001111 if ((r = mpt_attach(pdev,id)) != 0)
1112 return r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001113
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001114 ioc = pci_get_drvdata(pdev);
Moore, Eric Dean d335cc32005-04-30 17:09:38 -05001115 ioc->DoneCtx = mptfcDoneCtx;
1116 ioc->TaskCtx = mptfcTaskCtx;
1117 ioc->InternalCtx = mptfcInternalCtx;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001118
1119 /* Added sanity check on readiness of the MPT adapter.
1120 */
1121 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1122 printk(MYIOC_s_WARN_FMT
1123 "Skipping because it's not operational!\n",
1124 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001125 error = -ENODEV;
1126 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001127 }
1128
1129 if (!ioc->active) {
1130 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1131 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001132 error = -ENODEV;
1133 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001134 }
1135
1136 /* Sanity check - ensure at least 1 port is INITIATOR capable
1137 */
1138 ioc_cap = 0;
1139 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1140 if (ioc->pfacts[ii].ProtocolFlags &
1141 MPI_PORTFACTS_PROTOCOL_INITIATOR)
1142 ioc_cap ++;
1143 }
1144
1145 if (!ioc_cap) {
1146 printk(MYIOC_s_WARN_FMT
1147 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1148 ioc->name, ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001149 return 0;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001150 }
1151
1152 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
1153
1154 if (!sh) {
1155 printk(MYIOC_s_WARN_FMT
1156 "Unable to register controller with SCSI subsystem\n",
1157 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001158 error = -1;
1159 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001160 }
1161
Michael Reed80d3ac72006-05-24 15:07:09 -05001162 spin_lock_init(&ioc->fc_rescan_work_lock);
David Howellsc4028952006-11-22 14:57:56 +00001163 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
1164 INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
Michael Reed05e8ec12006-01-13 14:31:54 -06001165
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001166 spin_lock_irqsave(&ioc->FreeQlock, flags);
1167
1168 /* Attach the SCSI Host to the IOC structure
1169 */
1170 ioc->sh = sh;
1171
1172 sh->io_port = 0;
1173 sh->n_io_port = 0;
1174 sh->irq = 0;
1175
1176 /* set 16 byte cdb's */
1177 sh->max_cmd_len = 16;
1178
Eric Moore793955f2007-01-29 09:42:20 -07001179 sh->max_id = ioc->pfacts->MaxDevices;
1180 sh->max_lun = max_lun;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001181
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001182 sh->this_id = ioc->pfacts[0].PortSCSIID;
1183
1184 /* Required entry.
1185 */
1186 sh->unique_id = ioc->id;
1187
1188 /* Verify that we won't exceed the maximum
1189 * number of chain buffers
1190 * We can optimize: ZZ = req_sz/sizeof(SGE)
1191 * For 32bit SGE's:
1192 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1193 * + (req_sz - 64)/sizeof(SGE)
1194 * A slightly different algorithm is required for
1195 * 64bit SGEs.
1196 */
1197 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
1198 if (sizeof(dma_addr_t) == sizeof(u64)) {
1199 numSGE = (scale - 1) *
1200 (ioc->facts.MaxChainDepth-1) + scale +
1201 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
1202 sizeof(u32));
1203 } else {
1204 numSGE = 1 + (scale - 1) *
1205 (ioc->facts.MaxChainDepth-1) + scale +
1206 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
1207 sizeof(u32));
1208 }
1209
1210 if (numSGE < sh->sg_tablesize) {
1211 /* Reset this value */
1212 dprintk((MYIOC_s_INFO_FMT
1213 "Resetting sg_tablesize to %d from %d\n",
1214 ioc->name, numSGE, sh->sg_tablesize));
1215 sh->sg_tablesize = numSGE;
1216 }
1217
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001218 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1219
1220 hd = (MPT_SCSI_HOST *) sh->hostdata;
1221 hd->ioc = ioc;
1222
1223 /* SCSI needs scsi_cmnd lookup table!
1224 * (with size equal to req_depth*PtrSz!)
1225 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001226 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
1227 if (!hd->ScsiLookup) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001228 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001229 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001230 }
1231
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001232 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
1233 ioc->name, hd->ScsiLookup));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001234
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001235 /* Clear the TM flags
1236 */
1237 hd->tmPending = 0;
1238 hd->tmState = TM_STATE_NONE;
1239 hd->resetPending = 0;
1240 hd->abortSCpnt = NULL;
1241
1242 /* Clear the pointer used to store
1243 * single-threaded commands, i.e., those
1244 * issued during a bus scan, dv and
1245 * configuration pages.
1246 */
1247 hd->cmdPtr = NULL;
1248
1249 /* Initialize this SCSI Hosts' timers
1250 * To use, set the timer expires field
1251 * and add_timer
1252 */
1253 init_timer(&hd->timer);
1254 hd->timer.data = (unsigned long) hd;
1255 hd->timer.function = mptscsih_timer_expired;
1256
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001257 init_waitqueue_head(&hd->scandv_waitq);
1258 hd->scandv_wait_done = 0;
1259 hd->last_queue_full = 0;
1260
Michael Reed05e8ec12006-01-13 14:31:54 -06001261 sh->transportt = mptfc_transport_template;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001262 error = scsi_add_host (sh, &ioc->pcidev->dev);
1263 if(error) {
1264 dprintk((KERN_ERR MYNAM
1265 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001266 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001267 }
1268
Moore, Eric65207fe2006-04-21 16:14:35 -06001269 /* initialize workqueue */
1270
1271 snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d",
1272 sh->host_no);
1273 ioc->fc_rescan_work_q =
1274 create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
1275 if (!ioc->fc_rescan_work_q)
1276 goto out_mptfc_probe;
1277
1278 /*
Michael Reed80d3ac72006-05-24 15:07:09 -05001279 * Pre-fetch FC port WWN and stuff...
1280 * (FCPortPage0_t stuff)
1281 */
1282 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1283 (void) mptfc_GetFcPortPage0(ioc, ii);
1284 }
Michael Reedca2f9382006-05-24 15:07:24 -05001285 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001286
1287 /*
Moore, Eric65207fe2006-04-21 16:14:35 -06001288 * scan for rports -
1289 * by doing it via the workqueue, some locking is eliminated
1290 */
1291
Moore, Eric65207fe2006-04-21 16:14:35 -06001292 queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
1293 flush_workqueue(ioc->fc_rescan_work_q);
Michael Reed05e8ec12006-01-13 14:31:54 -06001294
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001295 return 0;
1296
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001297out_mptfc_probe:
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001298
1299 mptscsih_remove(pdev);
1300 return error;
1301}
1302
1303static struct pci_driver mptfc_driver = {
1304 .name = "mptfc",
1305 .id_table = mptfc_pci_table,
1306 .probe = mptfc_probe,
Michael Reed05e8ec12006-01-13 14:31:54 -06001307 .remove = __devexit_p(mptfc_remove),
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001308 .shutdown = mptscsih_shutdown,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001309#ifdef CONFIG_PM
1310 .suspend = mptscsih_suspend,
1311 .resume = mptscsih_resume,
1312#endif
1313};
1314
Michael Reed80d3ac72006-05-24 15:07:09 -05001315static int
1316mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1317{
1318 MPT_SCSI_HOST *hd;
1319 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1320 unsigned long flags;
1321 int rc=1;
1322
1323 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
1324 ioc->name, event));
1325
1326 if (ioc->sh == NULL ||
1327 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
1328 return 1;
1329
1330 switch (event) {
1331 case MPI_EVENT_RESCAN:
1332 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1333 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001334 queue_work(ioc->fc_rescan_work_q,
1335 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001336 }
1337 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1338 break;
1339 default:
1340 rc = mptscsih_event_process(ioc,pEvReply);
1341 break;
1342 }
1343 return rc;
1344}
1345
1346static int
1347mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1348{
1349 int rc;
1350 unsigned long flags;
1351
1352 rc = mptscsih_ioc_reset(ioc,reset_phase);
1353 if (rc == 0)
1354 return rc;
1355
1356
1357 dtmprintk((KERN_WARNING MYNAM
1358 ": IOC %s_reset routed to FC host driver!\n",
1359 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
1360 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
1361
1362 if (reset_phase == MPT_IOC_SETUP_RESET) {
Michael Reed419835e2006-05-24 15:07:40 -05001363 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1364 if (ioc->fc_rescan_work_q) {
1365 queue_work(ioc->fc_rescan_work_q,
1366 &ioc->fc_setup_reset_work);
1367 }
1368 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
Michael Reed80d3ac72006-05-24 15:07:09 -05001369 }
1370
1371 else if (reset_phase == MPT_IOC_PRE_RESET) {
1372 }
1373
1374 else { /* MPT_IOC_POST_RESET */
Michael Reedca2f9382006-05-24 15:07:24 -05001375 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001376 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1377 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001378 queue_work(ioc->fc_rescan_work_q,
1379 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001380 }
1381 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1382 }
1383 return 1;
1384}
1385
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001386/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1387/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001388 * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001389 *
1390 * Returns 0 for success, non-zero for failure.
1391 */
1392static int __init
1393mptfc_init(void)
1394{
Michael Reed05e8ec12006-01-13 14:31:54 -06001395 int error;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001396
1397 show_mptmod_ver(my_NAME, my_VERSION);
1398
Michael Reedca2f9382006-05-24 15:07:24 -05001399 /* sanity check module parameters */
1400 if (mptfc_dev_loss_tmo <= 0)
Michael Reed05e8ec12006-01-13 14:31:54 -06001401 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
1402
1403 mptfc_transport_template =
1404 fc_attach_transport(&mptfc_transport_functions);
1405
1406 if (!mptfc_transport_template)
1407 return -ENODEV;
1408
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001409 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
1410 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
1411 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
1412
Michael Reed80d3ac72006-05-24 15:07:09 -05001413 if (mpt_event_register(mptfcDoneCtx, mptfc_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07001414 devtverboseprintk((KERN_INFO MYNAM
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001415 ": Registered for IOC event notifications\n"));
1416 }
1417
Michael Reed80d3ac72006-05-24 15:07:09 -05001418 if (mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset) == 0) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001419 dprintk((KERN_INFO MYNAM
1420 ": Registered for IOC reset notifications\n"));
1421 }
1422
Michael Reed05e8ec12006-01-13 14:31:54 -06001423 error = pci_register_driver(&mptfc_driver);
Michael Reed3bc7bf12006-01-25 18:05:18 -07001424 if (error)
Michael Reed05e8ec12006-01-13 14:31:54 -06001425 fc_release_transport(mptfc_transport_template);
Michael Reed05e8ec12006-01-13 14:31:54 -06001426
1427 return error;
1428}
1429
1430/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1431/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001432 * mptfc_remove - Remove fc infrastructure for devices
Michael Reed05e8ec12006-01-13 14:31:54 -06001433 * @pdev: Pointer to pci_dev structure
1434 *
1435 */
Michael Reed3bc7bf12006-01-25 18:05:18 -07001436static void __devexit
1437mptfc_remove(struct pci_dev *pdev)
Michael Reed05e8ec12006-01-13 14:31:54 -06001438{
Moore, Eric65207fe2006-04-21 16:14:35 -06001439 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1440 struct mptfc_rport_info *p, *n;
1441 struct workqueue_struct *work_q;
1442 unsigned long flags;
Michael Reedca2f9382006-05-24 15:07:24 -05001443 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001444
1445 /* destroy workqueue */
1446 if ((work_q=ioc->fc_rescan_work_q)) {
1447 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1448 ioc->fc_rescan_work_q = NULL;
1449 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1450 destroy_workqueue(work_q);
1451 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001452
1453 fc_remove_host(ioc->sh);
1454
1455 list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
1456 list_del(&p->list);
1457 kfree(p);
1458 }
1459
Michael Reedca2f9382006-05-24 15:07:24 -05001460 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
1461 if (ioc->fc_data.fc_port_page1[ii].data) {
1462 pci_free_consistent(ioc->pcidev,
1463 ioc->fc_data.fc_port_page1[ii].pg_sz,
1464 (u8 *) ioc->fc_data.fc_port_page1[ii].data,
1465 ioc->fc_data.fc_port_page1[ii].dma);
1466 ioc->fc_data.fc_port_page1[ii].data = NULL;
1467 }
1468 }
1469
Michael Reed05e8ec12006-01-13 14:31:54 -06001470 mptscsih_remove(pdev);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001471}
1472
1473/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1474/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1475/**
1476 * mptfc_exit - Unregisters MPT adapter(s)
1477 *
1478 */
1479static void __exit
1480mptfc_exit(void)
1481{
1482 pci_unregister_driver(&mptfc_driver);
Michael Reed05e8ec12006-01-13 14:31:54 -06001483 fc_release_transport(mptfc_transport_template);
1484
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001485 mpt_reset_deregister(mptfcDoneCtx);
1486 dprintk((KERN_INFO MYNAM
1487 ": Deregistered for IOC reset notifications\n"));
1488
1489 mpt_event_deregister(mptfcDoneCtx);
1490 dprintk((KERN_INFO MYNAM
1491 ": Deregistered for IOC event notifications\n"));
1492
1493 mpt_deregister(mptfcInternalCtx);
1494 mpt_deregister(mptfcTaskCtx);
1495 mpt_deregister(mptfcDoneCtx);
1496}
1497
1498module_init(mptfc_init);
1499module_exit(mptfc_exit);