blob: c819c23b55b1aeb3ca477fd6c689c9cbc0134ff3 [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
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04007 * (mailto:mpt_linux_developer@lsil.com)
8 *
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/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46#include "linux_compat.h" /* linux-2.6 tweaks */
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
51#include <linux/kdev_t.h>
52#include <linux/blkdev.h>
53#include <linux/delay.h> /* for mdelay */
54#include <linux/interrupt.h> /* needed for in_interrupt() proto */
55#include <linux/reboot.h> /* notifier code */
56#include <linux/sched.h>
57#include <linux/workqueue.h>
Michael Reed05e8ec12006-01-13 14:31:54 -060058#include <linux/sort.h>
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040059
60#include <scsi/scsi.h>
61#include <scsi/scsi_cmnd.h>
62#include <scsi/scsi_device.h>
63#include <scsi/scsi_host.h>
64#include <scsi/scsi_tcq.h>
Michael Reed05e8ec12006-01-13 14:31:54 -060065#include <scsi/scsi_transport_fc.h>
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040066
67#include "mptbase.h"
68#include "mptscsih.h"
69
70/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71#define my_NAME "Fusion MPT FC Host driver"
72#define my_VERSION MPT_LINUX_VERSION_COMMON
73#define MYNAM "mptfc"
74
75MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040079
80/* Command line args */
Michael Reed05e8ec12006-01-13 14:31:54 -060081#define MPTFC_DEV_LOSS_TMO (60)
82static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO; /* reasonable default */
83module_param(mptfc_dev_loss_tmo, int, 0);
84MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "
85 " transport to wait for an rport to "
86 " return following a device loss event."
87 " Default=60.");
88
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040089static int mptfcDoneCtx = -1;
90static int mptfcTaskCtx = -1;
91static int mptfcInternalCtx = -1; /* Used only for internal commands */
92
Michael Reed3bc7bf12006-01-25 18:05:18 -070093static int mptfc_target_alloc(struct scsi_target *starget);
94static int mptfc_slave_alloc(struct scsi_device *sdev);
Michael Reed05e8ec12006-01-13 14:31:54 -060095static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
Michael Reed3bc7bf12006-01-25 18:05:18 -070096 void (*done)(struct scsi_cmnd *));
97static void mptfc_target_destroy(struct scsi_target *starget);
Michael Reed05e8ec12006-01-13 14:31:54 -060098static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
99static void __devexit mptfc_remove(struct pci_dev *pdev);
Michael Reed35508e42006-10-06 15:39:25 -0500100static int mptfc_abort(struct scsi_cmnd *SCpnt);
101static int mptfc_dev_reset(struct scsi_cmnd *SCpnt);
102static int mptfc_bus_reset(struct scsi_cmnd *SCpnt);
103static int mptfc_host_reset(struct scsi_cmnd *SCpnt);
Michael Reed05e8ec12006-01-13 14:31:54 -0600104
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400105static struct scsi_host_template mptfc_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700106 .module = THIS_MODULE,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400107 .proc_name = "mptfc",
108 .proc_info = mptscsih_proc_info,
109 .name = "MPT FC Host",
110 .info = mptscsih_info,
Michael Reed05e8ec12006-01-13 14:31:54 -0600111 .queuecommand = mptfc_qcmd,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700112 .target_alloc = mptfc_target_alloc,
Michael Reed05e8ec12006-01-13 14:31:54 -0600113 .slave_alloc = mptfc_slave_alloc,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400114 .slave_configure = mptscsih_slave_configure,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700115 .target_destroy = mptfc_target_destroy,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400116 .slave_destroy = mptscsih_slave_destroy,
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -0600117 .change_queue_depth = mptscsih_change_queue_depth,
Michael Reed35508e42006-10-06 15:39:25 -0500118 .eh_abort_handler = mptfc_abort,
119 .eh_device_reset_handler = mptfc_dev_reset,
120 .eh_bus_reset_handler = mptfc_bus_reset,
121 .eh_host_reset_handler = mptfc_host_reset,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400122 .bios_param = mptscsih_bios_param,
123 .can_queue = MPT_FC_CAN_QUEUE,
124 .this_id = -1,
125 .sg_tablesize = MPT_SCSI_SG_DEPTH,
126 .max_sectors = 8192,
127 .cmd_per_lun = 7,
128 .use_clustering = ENABLE_CLUSTERING,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400129};
130
131/****************************************************************************
132 * Supported hardware
133 */
134
135static struct pci_device_id mptfc_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -0600136 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC909,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400137 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600138 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400139 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600140 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929,
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_FC919X,
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_FC929X,
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_FC939X,
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600147 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600148 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949X,
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600149 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -0600150 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E,
Moore, Eric6d5b0c32006-01-13 16:25:26 -0700151 PCI_ANY_ID, PCI_ANY_ID },
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400152 {0} /* Terminating entry */
153};
154MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
155
Michael Reed05e8ec12006-01-13 14:31:54 -0600156static struct scsi_transport_template *mptfc_transport_template = NULL;
157
Adrian Bunk03fbcbc2006-01-25 02:00:52 +0100158static struct fc_function_template mptfc_transport_functions = {
Michael Reed05e8ec12006-01-13 14:31:54 -0600159 .dd_fcrport_size = 8,
160 .show_host_node_name = 1,
161 .show_host_port_name = 1,
162 .show_host_supported_classes = 1,
163 .show_host_port_id = 1,
164 .show_rport_supported_classes = 1,
165 .show_starget_node_name = 1,
166 .show_starget_port_name = 1,
167 .show_starget_port_id = 1,
168 .set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
169 .show_rport_dev_loss_tmo = 1,
Michael Reed5d947f22006-07-31 12:19:30 -0500170 .show_host_supported_speeds = 1,
171 .show_host_maxframe_size = 1,
172 .show_host_speed = 1,
173 .show_host_fabric_name = 1,
174 .show_host_port_type = 1,
175 .show_host_port_state = 1,
176 .show_host_symbolic_name = 1,
Michael Reed05e8ec12006-01-13 14:31:54 -0600177};
178
Michael Reed35508e42006-10-06 15:39:25 -0500179static int
180mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
181 int (*func)(struct scsi_cmnd *SCpnt),
182 const char *caller)
183{
184 struct scsi_device *sdev = SCpnt->device;
185 struct Scsi_Host *shost = sdev->host;
186 struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
187 unsigned long flags;
188 int ready;
189
190 spin_lock_irqsave(shost->host_lock, flags);
191 while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
192 spin_unlock_irqrestore(shost->host_lock, flags);
193 dfcprintk ((MYIOC_s_INFO_FMT
194 "mptfc_block_error_handler.%d: %d:%d, port status is "
195 "DID_IMM_RETRY, deferring %s recovery.\n",
196 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
197 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
198 SCpnt->device->id,SCpnt->device->lun,caller));
199 msleep(1000);
200 spin_lock_irqsave(shost->host_lock, flags);
201 }
202 spin_unlock_irqrestore(shost->host_lock, flags);
203
204 if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
205 dfcprintk ((MYIOC_s_INFO_FMT
206 "%s.%d: %d:%d, failing recovery, "
207 "port state %d, vdev %p.\n", caller,
208 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
209 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
210 SCpnt->device->id,SCpnt->device->lun,ready,
211 SCpnt->device->hostdata));
212 return FAILED;
213 }
214 dfcprintk ((MYIOC_s_INFO_FMT
215 "%s.%d: %d:%d, executing recovery.\n", caller,
216 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
217 ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
218 SCpnt->device->id,SCpnt->device->lun));
219 return (*func)(SCpnt);
220}
221
222static int
223mptfc_abort(struct scsi_cmnd *SCpnt)
224{
225 return
226 mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
227}
228
229static int
230mptfc_dev_reset(struct scsi_cmnd *SCpnt)
231{
232 return
233 mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
234}
235
236static int
237mptfc_bus_reset(struct scsi_cmnd *SCpnt)
238{
239 return
240 mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
241}
242
243static int
244mptfc_host_reset(struct scsi_cmnd *SCpnt)
245{
246 return
247 mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
248}
249
Michael Reed05e8ec12006-01-13 14:31:54 -0600250static void
251mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
252{
253 if (timeout > 0)
254 rport->dev_loss_tmo = timeout;
255 else
256 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
257}
258
259static int
260mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
261{
262 FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
263 FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
264
265 if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
266 if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
267 return 0;
268 if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
269 return -1;
270 return 1;
271 }
272 if ((*aa)->CurrentBus < (*bb)->CurrentBus)
273 return -1;
274 return 1;
275}
276
277static int
278mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
279 void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
280{
281 ConfigPageHeader_t hdr;
282 CONFIGPARMS cfg;
283 FCDevicePage0_t *ppage0_alloc, *fc;
284 dma_addr_t page0_dma;
285 int data_sz;
286 int ii;
287
288 FCDevicePage0_t *p0_array=NULL, *p_p0;
289 FCDevicePage0_t **pp0_array=NULL, **p_pp0;
290
291 int rc = -ENOMEM;
292 U32 port_id = 0xffffff;
293 int num_targ = 0;
294 int max_bus = ioc->facts.MaxBuses;
295 int max_targ = ioc->facts.MaxDevices;
296
297 if (max_bus == 0 || max_targ == 0)
298 goto out;
299
300 data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
301 p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL);
302 if (!p0_array)
303 goto out;
304
305 data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
306 p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
307 if (!pp0_array)
308 goto out;
309
310 do {
311 /* Get FC Device Page 0 header */
312 hdr.PageVersion = 0;
313 hdr.PageLength = 0;
314 hdr.PageNumber = 0;
315 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
316 cfg.cfghdr.hdr = &hdr;
317 cfg.physAddr = -1;
318 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
319 cfg.dir = 0;
320 cfg.pageAddr = port_id;
321 cfg.timeout = 0;
322
323 if ((rc = mpt_config(ioc, &cfg)) != 0)
324 break;
325
326 if (hdr.PageLength <= 0)
327 break;
328
329 data_sz = hdr.PageLength * 4;
330 ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
331 &page0_dma);
332 rc = -ENOMEM;
333 if (!ppage0_alloc)
334 break;
335
336 cfg.physAddr = page0_dma;
337 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
338
339 if ((rc = mpt_config(ioc, &cfg)) == 0) {
340 ppage0_alloc->PortIdentifier =
341 le32_to_cpu(ppage0_alloc->PortIdentifier);
342
343 ppage0_alloc->WWNN.Low =
344 le32_to_cpu(ppage0_alloc->WWNN.Low);
345
346 ppage0_alloc->WWNN.High =
347 le32_to_cpu(ppage0_alloc->WWNN.High);
348
349 ppage0_alloc->WWPN.Low =
350 le32_to_cpu(ppage0_alloc->WWPN.Low);
351
352 ppage0_alloc->WWPN.High =
353 le32_to_cpu(ppage0_alloc->WWPN.High);
354
355 ppage0_alloc->BBCredit =
356 le16_to_cpu(ppage0_alloc->BBCredit);
357
358 ppage0_alloc->MaxRxFrameSize =
359 le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
360
361 port_id = ppage0_alloc->PortIdentifier;
362 num_targ++;
363 *p_p0 = *ppage0_alloc; /* save data */
364 *p_pp0++ = p_p0++; /* save addr */
365 }
366 pci_free_consistent(ioc->pcidev, data_sz,
367 (u8 *) ppage0_alloc, page0_dma);
368 if (rc != 0)
369 break;
370
371 } while (port_id <= 0xff0000);
372
373 if (num_targ) {
374 /* sort array */
375 if (num_targ > 1)
376 sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
377 mptfc_FcDevPage0_cmp_func, NULL);
378 /* call caller's func for each targ */
379 for (ii = 0; ii < num_targ; ii++) {
380 fc = *(pp0_array+ii);
381 func(ioc, ioc_port, fc);
382 }
383 }
384
385 out:
Jesper Juhl8f760782006-06-27 02:55:06 -0700386 kfree(pp0_array);
387 kfree(p0_array);
Michael Reed05e8ec12006-01-13 14:31:54 -0600388 return rc;
389}
390
391static int
392mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
393{
394 /* not currently usable */
395 if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
396 MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
397 return -1;
398
399 if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
400 return -1;
401
402 if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
403 return -1;
404
405 /*
406 * board data structure already normalized to platform endianness
407 * shifted to avoid unaligned access on 64 bit architecture
408 */
409 rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
410 rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
411 rid->port_id = pg0->PortIdentifier;
412 rid->roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600413
414 return 0;
415}
416
417static void
418mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
419{
420 struct fc_rport_identifiers rport_ids;
421 struct fc_rport *rport;
422 struct mptfc_rport_info *ri;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700423 int new_ri = 1;
Moore, Eric65207fe2006-04-21 16:14:35 -0600424 u64 pn, nn;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700425 VirtTarget *vtarget;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500426 u32 roles = FC_RPORT_ROLE_UNKNOWN;
Michael Reed05e8ec12006-01-13 14:31:54 -0600427
428 if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
429 return;
430
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500431 roles |= FC_RPORT_ROLE_FCP_TARGET;
432 if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
433 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
434
Michael Reed05e8ec12006-01-13 14:31:54 -0600435 /* scan list looking for a match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600436 list_for_each_entry(ri, &ioc->fc_rports, list) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700437 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
438 if (pn == rport_ids.port_name) { /* match */
Michael Reed05e8ec12006-01-13 14:31:54 -0600439 list_move_tail(&ri->list, &ioc->fc_rports);
Michael Reed3bc7bf12006-01-25 18:05:18 -0700440 new_ri = 0;
Michael Reed05e8ec12006-01-13 14:31:54 -0600441 break;
442 }
443 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700444 if (new_ri) { /* allocate one */
Michael Reed05e8ec12006-01-13 14:31:54 -0600445 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
446 if (!ri)
447 return;
Michael Reed05e8ec12006-01-13 14:31:54 -0600448 list_add_tail(&ri->list, &ioc->fc_rports);
449 }
450
451 ri->pg0 = *pg0; /* add/update pg0 data */
452 ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
453
Michael Reed3bc7bf12006-01-25 18:05:18 -0700454 /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
Michael Reed05e8ec12006-01-13 14:31:54 -0600455 if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
456 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700457 rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
Michael Reed05e8ec12006-01-13 14:31:54 -0600458 if (rport) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700459 ri->rport = rport;
460 if (new_ri) /* may have been reset by user */
461 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
Michael Reed05e8ec12006-01-13 14:31:54 -0600462 /*
463 * if already mapped, remap here. If not mapped,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700464 * target_alloc will allocate vtarget and map,
465 * slave_alloc will fill in vdev from vtarget.
Michael Reed05e8ec12006-01-13 14:31:54 -0600466 */
Michael Reed3bc7bf12006-01-25 18:05:18 -0700467 if (ri->starget) {
468 vtarget = ri->starget->hostdata;
469 if (vtarget) {
470 vtarget->target_id = pg0->CurrentTargetID;
471 vtarget->bus_id = pg0->CurrentBus;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700472 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600473 }
Moore, Eric65207fe2006-04-21 16:14:35 -0600474 *((struct mptfc_rport_info **)rport->dd_data) = ri;
mdr@sgi.com6dd727d2006-05-01 13:07:04 -0500475 /* scan will be scheduled once rport becomes a target */
476 fc_remote_port_rolechg(rport,roles);
Moore, Eric65207fe2006-04-21 16:14:35 -0600477
478 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
479 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700480 dfcprintk ((MYIOC_s_INFO_FMT
481 "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600482 "rport tid %d, tmo %d\n",
Michael Reed3bc7bf12006-01-25 18:05:18 -0700483 ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700484 ioc->sh->host_no,
Michael Reed05e8ec12006-01-13 14:31:54 -0600485 pg0->PortIdentifier,
Moore, Eric65207fe2006-04-21 16:14:35 -0600486 (unsigned long long)nn,
487 (unsigned long long)pn,
Michael Reed05e8ec12006-01-13 14:31:54 -0600488 pg0->CurrentTargetID,
489 ri->rport->scsi_target_id,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700490 ri->rport->dev_loss_tmo));
Michael Reed05e8ec12006-01-13 14:31:54 -0600491 } else {
492 list_del(&ri->list);
493 kfree(ri);
494 ri = NULL;
495 }
496 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600497}
498
499/*
Michael Reed3bc7bf12006-01-25 18:05:18 -0700500 * OS entry point to allow for host driver to free allocated memory
501 * Called if no device present or device being unloaded
502 */
503static void
504mptfc_target_destroy(struct scsi_target *starget)
505{
506 struct fc_rport *rport;
507 struct mptfc_rport_info *ri;
508
509 rport = starget_to_rport(starget);
510 if (rport) {
511 ri = *((struct mptfc_rport_info **)rport->dd_data);
512 if (ri) /* better be! */
513 ri->starget = NULL;
514 }
515 if (starget->hostdata)
516 kfree(starget->hostdata);
517 starget->hostdata = NULL;
518}
519
520/*
521 * OS entry point to allow host driver to alloc memory
522 * for each scsi target. Called once per device the bus scan.
523 * Return non-zero if allocation fails.
524 */
525static int
526mptfc_target_alloc(struct scsi_target *starget)
527{
528 VirtTarget *vtarget;
529 struct fc_rport *rport;
530 struct mptfc_rport_info *ri;
531 int rc;
532
533 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
534 if (!vtarget)
535 return -ENOMEM;
536 starget->hostdata = vtarget;
537
538 rc = -ENODEV;
539 rport = starget_to_rport(starget);
540 if (rport) {
541 ri = *((struct mptfc_rport_info **)rport->dd_data);
542 if (ri) { /* better be! */
543 vtarget->target_id = ri->pg0.CurrentTargetID;
544 vtarget->bus_id = ri->pg0.CurrentBus;
545 ri->starget = starget;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700546 rc = 0;
547 }
548 }
549 if (rc != 0) {
550 kfree(vtarget);
551 starget->hostdata = NULL;
552 }
553
554 return rc;
555}
556
557/*
Michael Reed05e8ec12006-01-13 14:31:54 -0600558 * OS entry point to allow host driver to alloc memory
559 * for each scsi device. Called once per device the bus scan.
560 * Return non-zero if allocation fails.
561 * Init memory once per LUN.
562 */
Adrian Bunk03fbcbc2006-01-25 02:00:52 +0100563static int
Michael Reed05e8ec12006-01-13 14:31:54 -0600564mptfc_slave_alloc(struct scsi_device *sdev)
565{
566 MPT_SCSI_HOST *hd;
567 VirtTarget *vtarget;
568 VirtDevice *vdev;
569 struct scsi_target *starget;
570 struct fc_rport *rport;
Michael Reed05e8ec12006-01-13 14:31:54 -0600571
572
Moore, Eric65207fe2006-04-21 16:14:35 -0600573 starget = scsi_target(sdev);
574 rport = starget_to_rport(starget);
Michael Reed05e8ec12006-01-13 14:31:54 -0600575
576 if (!rport || fc_remote_port_chkready(rport))
577 return -ENXIO;
578
579 hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
580
Michael Reed3bc7bf12006-01-25 18:05:18 -0700581 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Michael Reed05e8ec12006-01-13 14:31:54 -0600582 if (!vdev) {
583 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
584 hd->ioc->name, sizeof(VirtDevice));
585 return -ENOMEM;
586 }
Michael Reed05e8ec12006-01-13 14:31:54 -0600587
Michael Reed05e8ec12006-01-13 14:31:54 -0600588
Michael Reed05e8ec12006-01-13 14:31:54 -0600589 sdev->hostdata = vdev;
Michael Reed05e8ec12006-01-13 14:31:54 -0600590 vtarget = starget->hostdata;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700591
Michael Reed05e8ec12006-01-13 14:31:54 -0600592 if (vtarget->num_luns == 0) {
Michael Reed3bc7bf12006-01-25 18:05:18 -0700593 vtarget->ioc_id = hd->ioc->id;
Eric Mooreba856d32006-07-11 17:34:01 -0600594 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
Michael Reed05e8ec12006-01-13 14:31:54 -0600595 hd->Targets[sdev->id] = vtarget;
596 }
597
Michael Reed05e8ec12006-01-13 14:31:54 -0600598 vdev->vtarget = vtarget;
Michael Reed05e8ec12006-01-13 14:31:54 -0600599 vdev->lun = sdev->lun;
Michael Reed05e8ec12006-01-13 14:31:54 -0600600
Michael Reed05e8ec12006-01-13 14:31:54 -0600601 vtarget->num_luns++;
602
Moore, Eric65207fe2006-04-21 16:14:35 -0600603
Moore, Eric914c2d82006-03-14 09:19:36 -0700604#ifdef DMPT_DEBUG_FC
Moore, Eric65207fe2006-04-21 16:14:35 -0600605 {
606 u64 nn, pn;
Moore, Eric914c2d82006-03-14 09:19:36 -0700607 struct mptfc_rport_info *ri;
608 ri = *((struct mptfc_rport_info **)rport->dd_data);
Moore, Eric65207fe2006-04-21 16:14:35 -0600609 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
610 nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
Michael Reed3bc7bf12006-01-25 18:05:18 -0700611 dfcprintk ((MYIOC_s_INFO_FMT
612 "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
Michael Reed05e8ec12006-01-13 14:31:54 -0600613 "CurrentTargetID %d, %x %llx %llx\n",
Moore, Eric914c2d82006-03-14 09:19:36 -0700614 hd->ioc->name,
Michael Reed3bc7bf12006-01-25 18:05:18 -0700615 sdev->host->host_no,
616 vtarget->num_luns,
617 sdev->id, ri->pg0.CurrentTargetID,
Moore, Eric65207fe2006-04-21 16:14:35 -0600618 ri->pg0.PortIdentifier,
619 (unsigned long long)pn,
620 (unsigned long long)nn));
Moore, Eric914c2d82006-03-14 09:19:36 -0700621 }
622#endif
Michael Reed05e8ec12006-01-13 14:31:54 -0600623
624 return 0;
625}
626
627static int
628mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
629{
Michael Reed3bc7bf12006-01-25 18:05:18 -0700630 struct mptfc_rport_info *ri;
Michael Reed05e8ec12006-01-13 14:31:54 -0600631 struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
632 int err;
633
634 err = fc_remote_port_chkready(rport);
635 if (unlikely(err)) {
636 SCpnt->result = err;
637 done(SCpnt);
638 return 0;
639 }
Michael Reed3bc7bf12006-01-25 18:05:18 -0700640
Michael Reed35508e42006-10-06 15:39:25 -0500641 if (!SCpnt->device->hostdata) { /* vdev */
642 SCpnt->result = DID_NO_CONNECT << 16;
643 done(SCpnt);
644 return 0;
645 }
646
Moore, Eric65207fe2006-04-21 16:14:35 -0600647 /* dd_data is null until finished adding target */
648 ri = *((struct mptfc_rport_info **)rport->dd_data);
649 if (unlikely(!ri)) {
650 dfcprintk ((MYIOC_s_INFO_FMT
651 "mptfc_qcmd.%d: %d:%d, dd_data is null.\n",
652 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
653 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
654 SCpnt->device->id,SCpnt->device->lun));
655 SCpnt->result = DID_IMM_RETRY << 16;
656 done(SCpnt);
657 return 0;
658 }
659
660 err = mptscsih_qcmd(SCpnt,done);
661#ifdef DMPT_DEBUG_FC
662 if (unlikely(err)) {
663 dfcprintk ((MYIOC_s_INFO_FMT
Michael Reed419835e2006-05-24 15:07:40 -0500664 "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero, (%x).\n",
Moore, Eric65207fe2006-04-21 16:14:35 -0600665 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
666 ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
Michael Reed419835e2006-05-24 15:07:40 -0500667 SCpnt->device->id,SCpnt->device->lun,err));
Moore, Eric65207fe2006-04-21 16:14:35 -0600668 }
669#endif
670 return err;
Michael Reed05e8ec12006-01-13 14:31:54 -0600671}
672
Michael Reed80d3ac72006-05-24 15:07:09 -0500673/*
674 * mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
675 * @ioc: Pointer to MPT_ADAPTER structure
676 * @portnum: IOC Port number
677 *
678 * Return: 0 for success
679 * -ENOMEM if no memory available
680 * -EPERM if not allowed due to ISR context
681 * -EAGAIN if no msg frames currently available
682 * -EFAULT for non-successful reply or no reply (timeout)
683 * -EINVAL portnum arg out of range (hardwired to two elements)
684 */
685static int
686mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
687{
688 ConfigPageHeader_t hdr;
689 CONFIGPARMS cfg;
690 FCPortPage0_t *ppage0_alloc;
691 FCPortPage0_t *pp0dest;
692 dma_addr_t page0_dma;
693 int data_sz;
694 int copy_sz;
695 int rc;
696 int count = 400;
697
698 if (portnum > 1)
699 return -EINVAL;
700
701 /* Get FCPort Page 0 header */
702 hdr.PageVersion = 0;
703 hdr.PageLength = 0;
704 hdr.PageNumber = 0;
705 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
706 cfg.cfghdr.hdr = &hdr;
707 cfg.physAddr = -1;
708 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
709 cfg.dir = 0;
710 cfg.pageAddr = portnum;
711 cfg.timeout = 0;
712
713 if ((rc = mpt_config(ioc, &cfg)) != 0)
714 return rc;
715
716 if (hdr.PageLength == 0)
717 return 0;
718
719 data_sz = hdr.PageLength * 4;
720 rc = -ENOMEM;
721 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
722 if (ppage0_alloc) {
723
724 try_again:
725 memset((u8 *)ppage0_alloc, 0, data_sz);
726 cfg.physAddr = page0_dma;
727 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
728
729 if ((rc = mpt_config(ioc, &cfg)) == 0) {
730 /* save the data */
731 pp0dest = &ioc->fc_port_page0[portnum];
732 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
733 memcpy(pp0dest, ppage0_alloc, copy_sz);
734
735 /*
736 * Normalize endianness of structure data,
737 * by byte-swapping all > 1 byte fields!
738 */
739 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
740 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
741 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
742 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
743 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
744 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
745 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
746 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
747 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
748 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
749 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
750 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
751 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
752 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
753 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
754 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
755
756 /*
757 * if still doing discovery,
758 * hang loose a while until finished
759 */
Michael Reed77d88ee2006-07-31 12:19:40 -0500760 if ((pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) ||
761 (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE &&
762 (pp0dest->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK)
763 == MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT)) {
Michael Reed80d3ac72006-05-24 15:07:09 -0500764 if (count-- > 0) {
Michael Reedd6be06c2006-05-24 15:07:57 -0500765 msleep(100);
Michael Reed80d3ac72006-05-24 15:07:09 -0500766 goto try_again;
767 }
768 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
769 " complete.\n",
770 ioc->name);
771 }
772 }
773
774 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
775 }
776
777 return rc;
778}
779
Michael Reedca2f9382006-05-24 15:07:24 -0500780static int
781mptfc_WriteFcPortPage1(MPT_ADAPTER *ioc, int portnum)
782{
783 ConfigPageHeader_t hdr;
784 CONFIGPARMS cfg;
785 int rc;
786
787 if (portnum > 1)
788 return -EINVAL;
789
790 if (!(ioc->fc_data.fc_port_page1[portnum].data))
791 return -EINVAL;
792
793 /* get fcport page 1 header */
794 hdr.PageVersion = 0;
795 hdr.PageLength = 0;
796 hdr.PageNumber = 1;
797 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
798 cfg.cfghdr.hdr = &hdr;
799 cfg.physAddr = -1;
800 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
801 cfg.dir = 0;
802 cfg.pageAddr = portnum;
803 cfg.timeout = 0;
804
805 if ((rc = mpt_config(ioc, &cfg)) != 0)
806 return rc;
807
808 if (hdr.PageLength == 0)
809 return -ENODEV;
810
811 if (hdr.PageLength*4 != ioc->fc_data.fc_port_page1[portnum].pg_sz)
812 return -EINVAL;
813
814 cfg.physAddr = ioc->fc_data.fc_port_page1[portnum].dma;
815 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
816 cfg.dir = 1;
817
818 rc = mpt_config(ioc, &cfg);
819
820 return rc;
821}
822
823static int
824mptfc_GetFcPortPage1(MPT_ADAPTER *ioc, int portnum)
825{
826 ConfigPageHeader_t hdr;
827 CONFIGPARMS cfg;
828 FCPortPage1_t *page1_alloc;
829 dma_addr_t page1_dma;
830 int data_sz;
831 int rc;
832
833 if (portnum > 1)
834 return -EINVAL;
835
836 /* get fcport page 1 header */
837 hdr.PageVersion = 0;
838 hdr.PageLength = 0;
839 hdr.PageNumber = 1;
840 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
841 cfg.cfghdr.hdr = &hdr;
842 cfg.physAddr = -1;
843 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
844 cfg.dir = 0;
845 cfg.pageAddr = portnum;
846 cfg.timeout = 0;
847
848 if ((rc = mpt_config(ioc, &cfg)) != 0)
849 return rc;
850
851 if (hdr.PageLength == 0)
852 return -ENODEV;
853
854start_over:
855
856 if (ioc->fc_data.fc_port_page1[portnum].data == NULL) {
857 data_sz = hdr.PageLength * 4;
858 if (data_sz < sizeof(FCPortPage1_t))
859 data_sz = sizeof(FCPortPage1_t);
860
861 page1_alloc = (FCPortPage1_t *) pci_alloc_consistent(ioc->pcidev,
862 data_sz,
863 &page1_dma);
864 if (!page1_alloc)
865 return -ENOMEM;
866 }
867 else {
868 page1_alloc = ioc->fc_data.fc_port_page1[portnum].data;
869 page1_dma = ioc->fc_data.fc_port_page1[portnum].dma;
870 data_sz = ioc->fc_data.fc_port_page1[portnum].pg_sz;
871 if (hdr.PageLength * 4 > data_sz) {
872 ioc->fc_data.fc_port_page1[portnum].data = NULL;
873 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
874 page1_alloc, page1_dma);
875 goto start_over;
876 }
877 }
878
879 memset(page1_alloc,0,data_sz);
880
881 cfg.physAddr = page1_dma;
882 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
883
884 if ((rc = mpt_config(ioc, &cfg)) == 0) {
885 ioc->fc_data.fc_port_page1[portnum].data = page1_alloc;
886 ioc->fc_data.fc_port_page1[portnum].pg_sz = data_sz;
887 ioc->fc_data.fc_port_page1[portnum].dma = page1_dma;
888 }
889 else {
890 ioc->fc_data.fc_port_page1[portnum].data = NULL;
891 pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
892 page1_alloc, page1_dma);
893 }
894
895 return rc;
896}
897
898static void
899mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
900{
901 int ii;
902 FCPortPage1_t *pp1;
903
904 #define MPTFC_FW_DEVICE_TIMEOUT (1)
905 #define MPTFC_FW_IO_PEND_TIMEOUT (1)
906 #define ON_FLAGS (MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY)
907 #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)
908
909 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
910 if (mptfc_GetFcPortPage1(ioc, ii) != 0)
911 continue;
912 pp1 = ioc->fc_data.fc_port_page1[ii].data;
913 if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)
914 && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)
915 && ((pp1->Flags & ON_FLAGS) == ON_FLAGS)
916 && ((pp1->Flags & OFF_FLAGS) == 0))
917 continue;
918 pp1->InitiatorDeviceTimeout = MPTFC_FW_DEVICE_TIMEOUT;
919 pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT;
920 pp1->Flags &= ~OFF_FLAGS;
921 pp1->Flags |= ON_FLAGS;
922 mptfc_WriteFcPortPage1(ioc, ii);
923 }
924}
925
926
Michael Reed05e8ec12006-01-13 14:31:54 -0600927static void
928mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
929{
Michael Reed5d947f22006-07-31 12:19:30 -0500930 unsigned class = 0;
931 unsigned cos = 0;
932 unsigned speed;
933 unsigned port_type;
934 unsigned port_state;
935 FCPortPage0_t *pp0;
936 struct Scsi_Host *sh;
937 char *sn;
Michael Reed05e8ec12006-01-13 14:31:54 -0600938
939 /* don't know what to do as only one scsi (fc) host was allocated */
940 if (portnum != 0)
941 return;
942
Michael Reed5d947f22006-07-31 12:19:30 -0500943 pp0 = &ioc->fc_port_page0[portnum];
944 sh = ioc->sh;
945
946 sn = fc_host_symbolic_name(sh);
947 snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",
948 ioc->prod_name,
949 MPT_FW_REV_MAGIC_ID_STRING,
950 ioc->facts.FWVersion.Word);
951
952 fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;
953
954 fc_host_maxframe_size(sh) = pp0->MaxFrameSize;
955
956 fc_host_node_name(sh) =
957 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
958
959 fc_host_port_name(sh) =
960 (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;
961
962 fc_host_port_id(sh) = pp0->PortIdentifier;
963
964 class = pp0->SupportedServiceClass;
Michael Reed05e8ec12006-01-13 14:31:54 -0600965 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
966 cos |= FC_COS_CLASS1;
967 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
968 cos |= FC_COS_CLASS2;
969 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
970 cos |= FC_COS_CLASS3;
Michael Reed5d947f22006-07-31 12:19:30 -0500971 fc_host_supported_classes(sh) = cos;
Michael Reed05e8ec12006-01-13 14:31:54 -0600972
Michael Reed5d947f22006-07-31 12:19:30 -0500973 if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)
974 speed = FC_PORTSPEED_1GBIT;
975 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)
976 speed = FC_PORTSPEED_2GBIT;
977 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)
978 speed = FC_PORTSPEED_4GBIT;
979 else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)
980 speed = FC_PORTSPEED_10GBIT;
981 else
982 speed = FC_PORTSPEED_UNKNOWN;
983 fc_host_speed(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -0600984
Michael Reed5d947f22006-07-31 12:19:30 -0500985 speed = 0;
986 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)
987 speed |= FC_PORTSPEED_1GBIT;
988 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
989 speed |= FC_PORTSPEED_2GBIT;
990 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
991 speed |= FC_PORTSPEED_4GBIT;
992 if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
993 speed |= FC_PORTSPEED_10GBIT;
994 fc_host_supported_speeds(sh) = speed;
Michael Reed05e8ec12006-01-13 14:31:54 -0600995
Michael Reed5d947f22006-07-31 12:19:30 -0500996 port_state = FC_PORTSTATE_UNKNOWN;
997 if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)
998 port_state = FC_PORTSTATE_ONLINE;
999 else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)
1000 port_state = FC_PORTSTATE_LINKDOWN;
1001 fc_host_port_state(sh) = port_state;
Michael Reed05e8ec12006-01-13 14:31:54 -06001002
Michael Reed5d947f22006-07-31 12:19:30 -05001003 port_type = FC_PORTTYPE_UNKNOWN;
1004 if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)
1005 port_type = FC_PORTTYPE_PTP;
1006 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)
1007 port_type = FC_PORTTYPE_LPORT;
1008 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)
1009 port_type = FC_PORTTYPE_NLPORT;
1010 else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)
1011 port_type = FC_PORTTYPE_NPORT;
1012 fc_host_port_type(sh) = port_type;
Michael Reed05e8ec12006-01-13 14:31:54 -06001013
Michael Reed5d947f22006-07-31 12:19:30 -05001014 fc_host_fabric_name(sh) =
1015 (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?
1016 (u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :
1017 (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
1018
Michael Reed05e8ec12006-01-13 14:31:54 -06001019}
1020
1021static void
David Howellsc4028952006-11-22 14:57:56 +00001022mptfc_setup_reset(struct work_struct *work)
Michael Reed419835e2006-05-24 15:07:40 -05001023{
David Howellsc4028952006-11-22 14:57:56 +00001024 MPT_ADAPTER *ioc =
1025 container_of(work, MPT_ADAPTER, fc_setup_reset_work);
Michael Reed419835e2006-05-24 15:07:40 -05001026 u64 pn;
1027 struct mptfc_rport_info *ri;
1028
1029 /* reset about to happen, delete (block) all rports */
1030 list_for_each_entry(ri, &ioc->fc_rports, list) {
1031 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1032 ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
1033 fc_remote_port_delete(ri->rport); /* won't sleep */
1034 ri->rport = NULL;
1035
1036 pn = (u64)ri->pg0.WWPN.High << 32 |
1037 (u64)ri->pg0.WWPN.Low;
1038 dfcprintk ((MYIOC_s_INFO_FMT
1039 "mptfc_setup_reset.%d: %llx deleted\n",
1040 ioc->name,
1041 ioc->sh->host_no,
1042 (unsigned long long)pn));
1043 }
1044 }
1045}
1046
1047static void
David Howellsc4028952006-11-22 14:57:56 +00001048mptfc_rescan_devices(struct work_struct *work)
Michael Reed05e8ec12006-01-13 14:31:54 -06001049{
David Howellsc4028952006-11-22 14:57:56 +00001050 MPT_ADAPTER *ioc =
1051 container_of(work, MPT_ADAPTER, fc_rescan_work);
Michael Reed05e8ec12006-01-13 14:31:54 -06001052 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001053 u64 pn;
Michael Reed05e8ec12006-01-13 14:31:54 -06001054 struct mptfc_rport_info *ri;
1055
Michael Reed3a0c56d2006-07-31 12:19:50 -05001056 /* start by tagging all ports as missing */
1057 list_for_each_entry(ri, &ioc->fc_rports, list) {
1058 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
1059 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
Michael Reed05e8ec12006-01-13 14:31:54 -06001060 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001061 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001062
Michael Reed3a0c56d2006-07-31 12:19:50 -05001063 /*
1064 * now rescan devices known to adapter,
1065 * will reregister existing rports
1066 */
1067 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1068 (void) mptfc_GetFcPortPage0(ioc, ii);
1069 mptfc_init_host_attr(ioc, ii); /* refresh */
1070 mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev);
1071 }
1072
1073 /* delete devices still missing */
1074 list_for_each_entry(ri, &ioc->fc_rports, list) {
1075 /* if newly missing, delete it */
1076 if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
1077
1078 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
1079 MPT_RPORT_INFO_FLAGS_MISSING);
1080 fc_remote_port_delete(ri->rport); /* won't sleep */
1081 ri->rport = NULL;
1082
1083 pn = (u64)ri->pg0.WWPN.High << 32 |
1084 (u64)ri->pg0.WWPN.Low;
1085 dfcprintk ((MYIOC_s_INFO_FMT
1086 "mptfc_rescan.%d: %llx deleted\n",
1087 ioc->name,
1088 ioc->sh->host_no,
1089 (unsigned long long)pn));
Michael Reed05e8ec12006-01-13 14:31:54 -06001090 }
Michael Reed3a0c56d2006-07-31 12:19:50 -05001091 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001092}
1093
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001094static int
1095mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1096{
1097 struct Scsi_Host *sh;
1098 MPT_SCSI_HOST *hd;
1099 MPT_ADAPTER *ioc;
1100 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001101 int ii;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001102 int numSGE = 0;
1103 int scale;
1104 int ioc_cap;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001105 int error=0;
1106 int r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001107
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001108 if ((r = mpt_attach(pdev,id)) != 0)
1109 return r;
Michael Reed05e8ec12006-01-13 14:31:54 -06001110
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001111 ioc = pci_get_drvdata(pdev);
Moore, Eric Dean d335cc32005-04-30 17:09:38 -05001112 ioc->DoneCtx = mptfcDoneCtx;
1113 ioc->TaskCtx = mptfcTaskCtx;
1114 ioc->InternalCtx = mptfcInternalCtx;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001115
1116 /* Added sanity check on readiness of the MPT adapter.
1117 */
1118 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1119 printk(MYIOC_s_WARN_FMT
1120 "Skipping because it's not operational!\n",
1121 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001122 error = -ENODEV;
1123 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001124 }
1125
1126 if (!ioc->active) {
1127 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1128 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001129 error = -ENODEV;
1130 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001131 }
1132
1133 /* Sanity check - ensure at least 1 port is INITIATOR capable
1134 */
1135 ioc_cap = 0;
1136 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1137 if (ioc->pfacts[ii].ProtocolFlags &
1138 MPI_PORTFACTS_PROTOCOL_INITIATOR)
1139 ioc_cap ++;
1140 }
1141
1142 if (!ioc_cap) {
1143 printk(MYIOC_s_WARN_FMT
1144 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1145 ioc->name, ioc);
Michael Reed05e8ec12006-01-13 14:31:54 -06001146 return -ENODEV;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001147 }
1148
1149 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
1150
1151 if (!sh) {
1152 printk(MYIOC_s_WARN_FMT
1153 "Unable to register controller with SCSI subsystem\n",
1154 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001155 error = -1;
1156 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001157 }
1158
Michael Reed80d3ac72006-05-24 15:07:09 -05001159 spin_lock_init(&ioc->fc_rescan_work_lock);
David Howellsc4028952006-11-22 14:57:56 +00001160 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
1161 INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
Michael Reed05e8ec12006-01-13 14:31:54 -06001162
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001163 spin_lock_irqsave(&ioc->FreeQlock, flags);
1164
1165 /* Attach the SCSI Host to the IOC structure
1166 */
1167 ioc->sh = sh;
1168
1169 sh->io_port = 0;
1170 sh->n_io_port = 0;
1171 sh->irq = 0;
1172
1173 /* set 16 byte cdb's */
1174 sh->max_cmd_len = 16;
1175
1176 sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
1177
1178 sh->max_lun = MPT_LAST_LUN + 1;
1179 sh->max_channel = 0;
1180 sh->this_id = ioc->pfacts[0].PortSCSIID;
1181
1182 /* Required entry.
1183 */
1184 sh->unique_id = ioc->id;
1185
1186 /* Verify that we won't exceed the maximum
1187 * number of chain buffers
1188 * We can optimize: ZZ = req_sz/sizeof(SGE)
1189 * For 32bit SGE's:
1190 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1191 * + (req_sz - 64)/sizeof(SGE)
1192 * A slightly different algorithm is required for
1193 * 64bit SGEs.
1194 */
1195 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
1196 if (sizeof(dma_addr_t) == sizeof(u64)) {
1197 numSGE = (scale - 1) *
1198 (ioc->facts.MaxChainDepth-1) + scale +
1199 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
1200 sizeof(u32));
1201 } else {
1202 numSGE = 1 + (scale - 1) *
1203 (ioc->facts.MaxChainDepth-1) + scale +
1204 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
1205 sizeof(u32));
1206 }
1207
1208 if (numSGE < sh->sg_tablesize) {
1209 /* Reset this value */
1210 dprintk((MYIOC_s_INFO_FMT
1211 "Resetting sg_tablesize to %d from %d\n",
1212 ioc->name, numSGE, sh->sg_tablesize));
1213 sh->sg_tablesize = numSGE;
1214 }
1215
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001216 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1217
1218 hd = (MPT_SCSI_HOST *) sh->hostdata;
1219 hd->ioc = ioc;
1220
1221 /* SCSI needs scsi_cmnd lookup table!
1222 * (with size equal to req_depth*PtrSz!)
1223 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001224 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
1225 if (!hd->ScsiLookup) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001226 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001227 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001228 }
1229
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001230 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
1231 ioc->name, hd->ScsiLookup));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001232
1233 /* Allocate memory for the device structures.
1234 * A non-Null pointer at an offset
1235 * indicates a device exists.
1236 * max_id = 1 + maximum id (hosts.h)
1237 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001238 hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
1239 if (!hd->Targets) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001240 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001241 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001242 }
1243
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001244 dprintk((KERN_INFO " vdev @ %p\n", hd->Targets));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001245
1246 /* Clear the TM flags
1247 */
1248 hd->tmPending = 0;
1249 hd->tmState = TM_STATE_NONE;
1250 hd->resetPending = 0;
1251 hd->abortSCpnt = NULL;
1252
1253 /* Clear the pointer used to store
1254 * single-threaded commands, i.e., those
1255 * issued during a bus scan, dv and
1256 * configuration pages.
1257 */
1258 hd->cmdPtr = NULL;
1259
1260 /* Initialize this SCSI Hosts' timers
1261 * To use, set the timer expires field
1262 * and add_timer
1263 */
1264 init_timer(&hd->timer);
1265 hd->timer.data = (unsigned long) hd;
1266 hd->timer.function = mptscsih_timer_expired;
1267
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001268 init_waitqueue_head(&hd->scandv_waitq);
1269 hd->scandv_wait_done = 0;
1270 hd->last_queue_full = 0;
1271
Michael Reed05e8ec12006-01-13 14:31:54 -06001272 sh->transportt = mptfc_transport_template;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001273 error = scsi_add_host (sh, &ioc->pcidev->dev);
1274 if(error) {
1275 dprintk((KERN_ERR MYNAM
1276 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001277 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001278 }
1279
Moore, Eric65207fe2006-04-21 16:14:35 -06001280 /* initialize workqueue */
1281
1282 snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d",
1283 sh->host_no);
1284 ioc->fc_rescan_work_q =
1285 create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
1286 if (!ioc->fc_rescan_work_q)
1287 goto out_mptfc_probe;
1288
1289 /*
Michael Reed80d3ac72006-05-24 15:07:09 -05001290 * Pre-fetch FC port WWN and stuff...
1291 * (FCPortPage0_t stuff)
1292 */
1293 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1294 (void) mptfc_GetFcPortPage0(ioc, ii);
1295 }
Michael Reedca2f9382006-05-24 15:07:24 -05001296 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001297
1298 /*
Moore, Eric65207fe2006-04-21 16:14:35 -06001299 * scan for rports -
1300 * by doing it via the workqueue, some locking is eliminated
1301 */
1302
Moore, Eric65207fe2006-04-21 16:14:35 -06001303 queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
1304 flush_workqueue(ioc->fc_rescan_work_q);
Michael Reed05e8ec12006-01-13 14:31:54 -06001305
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001306 return 0;
1307
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001308out_mptfc_probe:
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001309
1310 mptscsih_remove(pdev);
1311 return error;
1312}
1313
1314static struct pci_driver mptfc_driver = {
1315 .name = "mptfc",
1316 .id_table = mptfc_pci_table,
1317 .probe = mptfc_probe,
Michael Reed05e8ec12006-01-13 14:31:54 -06001318 .remove = __devexit_p(mptfc_remove),
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001319 .shutdown = mptscsih_shutdown,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001320#ifdef CONFIG_PM
1321 .suspend = mptscsih_suspend,
1322 .resume = mptscsih_resume,
1323#endif
1324};
1325
Michael Reed80d3ac72006-05-24 15:07:09 -05001326static int
1327mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1328{
1329 MPT_SCSI_HOST *hd;
1330 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1331 unsigned long flags;
1332 int rc=1;
1333
1334 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
1335 ioc->name, event));
1336
1337 if (ioc->sh == NULL ||
1338 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
1339 return 1;
1340
1341 switch (event) {
1342 case MPI_EVENT_RESCAN:
1343 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1344 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001345 queue_work(ioc->fc_rescan_work_q,
1346 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001347 }
1348 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1349 break;
1350 default:
1351 rc = mptscsih_event_process(ioc,pEvReply);
1352 break;
1353 }
1354 return rc;
1355}
1356
1357static int
1358mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1359{
1360 int rc;
1361 unsigned long flags;
1362
1363 rc = mptscsih_ioc_reset(ioc,reset_phase);
1364 if (rc == 0)
1365 return rc;
1366
1367
1368 dtmprintk((KERN_WARNING MYNAM
1369 ": IOC %s_reset routed to FC host driver!\n",
1370 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
1371 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
1372
1373 if (reset_phase == MPT_IOC_SETUP_RESET) {
Michael Reed419835e2006-05-24 15:07:40 -05001374 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1375 if (ioc->fc_rescan_work_q) {
1376 queue_work(ioc->fc_rescan_work_q,
1377 &ioc->fc_setup_reset_work);
1378 }
1379 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
Michael Reed80d3ac72006-05-24 15:07:09 -05001380 }
1381
1382 else if (reset_phase == MPT_IOC_PRE_RESET) {
1383 }
1384
1385 else { /* MPT_IOC_POST_RESET */
Michael Reedca2f9382006-05-24 15:07:24 -05001386 mptfc_SetFcPortPage1_defaults(ioc);
Michael Reed80d3ac72006-05-24 15:07:09 -05001387 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1388 if (ioc->fc_rescan_work_q) {
Michael Reed3a0c56d2006-07-31 12:19:50 -05001389 queue_work(ioc->fc_rescan_work_q,
1390 &ioc->fc_rescan_work);
Michael Reed80d3ac72006-05-24 15:07:09 -05001391 }
1392 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1393 }
1394 return 1;
1395}
1396
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001397/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1398/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001399 * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001400 *
1401 * Returns 0 for success, non-zero for failure.
1402 */
1403static int __init
1404mptfc_init(void)
1405{
Michael Reed05e8ec12006-01-13 14:31:54 -06001406 int error;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001407
1408 show_mptmod_ver(my_NAME, my_VERSION);
1409
Michael Reedca2f9382006-05-24 15:07:24 -05001410 /* sanity check module parameters */
1411 if (mptfc_dev_loss_tmo <= 0)
Michael Reed05e8ec12006-01-13 14:31:54 -06001412 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
1413
1414 mptfc_transport_template =
1415 fc_attach_transport(&mptfc_transport_functions);
1416
1417 if (!mptfc_transport_template)
1418 return -ENODEV;
1419
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001420 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
1421 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
1422 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
1423
Michael Reed80d3ac72006-05-24 15:07:09 -05001424 if (mpt_event_register(mptfcDoneCtx, mptfc_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07001425 devtverboseprintk((KERN_INFO MYNAM
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001426 ": Registered for IOC event notifications\n"));
1427 }
1428
Michael Reed80d3ac72006-05-24 15:07:09 -05001429 if (mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset) == 0) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001430 dprintk((KERN_INFO MYNAM
1431 ": Registered for IOC reset notifications\n"));
1432 }
1433
Michael Reed05e8ec12006-01-13 14:31:54 -06001434 error = pci_register_driver(&mptfc_driver);
Michael Reed3bc7bf12006-01-25 18:05:18 -07001435 if (error)
Michael Reed05e8ec12006-01-13 14:31:54 -06001436 fc_release_transport(mptfc_transport_template);
Michael Reed05e8ec12006-01-13 14:31:54 -06001437
1438 return error;
1439}
1440
1441/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1442/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001443 * mptfc_remove - Remove fc infrastructure for devices
Michael Reed05e8ec12006-01-13 14:31:54 -06001444 * @pdev: Pointer to pci_dev structure
1445 *
1446 */
Michael Reed3bc7bf12006-01-25 18:05:18 -07001447static void __devexit
1448mptfc_remove(struct pci_dev *pdev)
Michael Reed05e8ec12006-01-13 14:31:54 -06001449{
Moore, Eric65207fe2006-04-21 16:14:35 -06001450 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1451 struct mptfc_rport_info *p, *n;
1452 struct workqueue_struct *work_q;
1453 unsigned long flags;
Michael Reedca2f9382006-05-24 15:07:24 -05001454 int ii;
Moore, Eric65207fe2006-04-21 16:14:35 -06001455
1456 /* destroy workqueue */
1457 if ((work_q=ioc->fc_rescan_work_q)) {
1458 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1459 ioc->fc_rescan_work_q = NULL;
1460 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1461 destroy_workqueue(work_q);
1462 }
Michael Reed05e8ec12006-01-13 14:31:54 -06001463
1464 fc_remove_host(ioc->sh);
1465
1466 list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
1467 list_del(&p->list);
1468 kfree(p);
1469 }
1470
Michael Reedca2f9382006-05-24 15:07:24 -05001471 for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
1472 if (ioc->fc_data.fc_port_page1[ii].data) {
1473 pci_free_consistent(ioc->pcidev,
1474 ioc->fc_data.fc_port_page1[ii].pg_sz,
1475 (u8 *) ioc->fc_data.fc_port_page1[ii].data,
1476 ioc->fc_data.fc_port_page1[ii].dma);
1477 ioc->fc_data.fc_port_page1[ii].data = NULL;
1478 }
1479 }
1480
Michael Reed05e8ec12006-01-13 14:31:54 -06001481 mptscsih_remove(pdev);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001482}
1483
1484/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1485/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1486/**
1487 * mptfc_exit - Unregisters MPT adapter(s)
1488 *
1489 */
1490static void __exit
1491mptfc_exit(void)
1492{
1493 pci_unregister_driver(&mptfc_driver);
Michael Reed05e8ec12006-01-13 14:31:54 -06001494 fc_release_transport(mptfc_transport_template);
1495
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001496 mpt_reset_deregister(mptfcDoneCtx);
1497 dprintk((KERN_INFO MYNAM
1498 ": Deregistered for IOC reset notifications\n"));
1499
1500 mpt_event_deregister(mptfcDoneCtx);
1501 dprintk((KERN_INFO MYNAM
1502 ": Deregistered for IOC event notifications\n"));
1503
1504 mpt_deregister(mptfcInternalCtx);
1505 mpt_deregister(mptfcTaskCtx);
1506 mpt_deregister(mptfcDoneCtx);
1507}
1508
1509module_init(mptfc_init);
1510module_exit(mptfc_exit);