Blame view

drivers/scsi/isci/init.c 15.6 KB
6f231dda6   Dan Williams   isci: Intel(R) C6...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  /*
   * This file is provided under a dual BSD/GPLv2 license.  When using or
   * redistributing this file, you may do so under either license.
   *
   * GPL LICENSE SUMMARY
   *
   * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of version 2 of the GNU General Public License as
   * published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
   * The full GNU General Public License is included in this distribution
   * in the file called LICENSE.GPL.
   *
   * BSD LICENSE
   *
   * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   *   * Redistributions of source code must retain the above copyright
   *     notice, this list of conditions and the following disclaimer.
   *   * Redistributions in binary form must reproduce the above copyright
   *     notice, this list of conditions and the following disclaimer in
   *     the documentation and/or other materials provided with the
   *     distribution.
   *   * Neither the name of Intel Corporation nor the names of its
   *     contributors may be used to endorse or promote products derived
   *     from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/module.h>
d044af17a   Dan Williams   isci: Add support...
59
60
  #include <linux/firmware.h>
  #include <linux/efi.h>
6f231dda6   Dan Williams   isci: Intel(R) C6...
61
  #include <asm/string.h>
3a7bda830   Dave Jiang   [SCSI] isci: Addi...
62
  #include <scsi/scsi_host.h>
6f231dda6   Dan Williams   isci: Intel(R) C6...
63
64
  #include "isci.h"
  #include "task.h"
d044af17a   Dan Williams   isci: Add support...
65
  #include "probe_roms.h"
6f231dda6   Dan Williams   isci: Intel(R) C6...
66

98e2a5a3a   Dan Williams   [SCSI] isci: add ...
67
68
69
70
71
72
73
  #define MAJ 1
  #define MIN 0
  #define BUILD 0
  #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
  	__stringify(BUILD)
  
  MODULE_VERSION(DRV_VERSION);
6f231dda6   Dan Williams   isci: Intel(R) C6...
74
  static struct scsi_transport_template *isci_transport_template;
6f231dda6   Dan Williams   isci: Intel(R) C6...
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  
  static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = {
  	{ PCI_VDEVICE(INTEL, 0x1D61),},
  	{ PCI_VDEVICE(INTEL, 0x1D63),},
  	{ PCI_VDEVICE(INTEL, 0x1D65),},
  	{ PCI_VDEVICE(INTEL, 0x1D67),},
  	{ PCI_VDEVICE(INTEL, 0x1D69),},
  	{ PCI_VDEVICE(INTEL, 0x1D6B),},
  	{ PCI_VDEVICE(INTEL, 0x1D60),},
  	{ PCI_VDEVICE(INTEL, 0x1D62),},
  	{ PCI_VDEVICE(INTEL, 0x1D64),},
  	{ PCI_VDEVICE(INTEL, 0x1D66),},
  	{ PCI_VDEVICE(INTEL, 0x1D68),},
  	{ PCI_VDEVICE(INTEL, 0x1D6A),},
  	{}
  };
6f231dda6   Dan Williams   isci: Intel(R) C6...
91
  MODULE_DEVICE_TABLE(pci, isci_id_table);
6f231dda6   Dan Williams   isci: Intel(R) C6...
92
  /* linux isci specific settings */
6f231dda6   Dan Williams   isci: Intel(R) C6...
93

b5f18a201   Dave Jiang   isci: exposing us...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  unsigned char no_outbound_task_to = 20;
  module_param(no_outbound_task_to, byte, 0);
  MODULE_PARM_DESC(no_outbound_task_to, "No Outbound Task Timeout (1us incr)");
  
  u16 ssp_max_occ_to = 20;
  module_param(ssp_max_occ_to, ushort, 0);
  MODULE_PARM_DESC(ssp_max_occ_to, "SSP Max occupancy timeout (100us incr)");
  
  u16 stp_max_occ_to = 5;
  module_param(stp_max_occ_to, ushort, 0);
  MODULE_PARM_DESC(stp_max_occ_to, "STP Max occupancy timeout (100us incr)");
  
  u16 ssp_inactive_to = 5;
  module_param(ssp_inactive_to, ushort, 0);
  MODULE_PARM_DESC(ssp_inactive_to, "SSP inactivity timeout (100us incr)");
  
  u16 stp_inactive_to = 5;
  module_param(stp_inactive_to, ushort, 0);
  MODULE_PARM_DESC(stp_inactive_to, "STP inactivity timeout (100us incr)");
  
  unsigned char phy_gen = 3;
  module_param(phy_gen, byte, 0);
  MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)");
7000f7c71   Andrzej Jakowski   [SCSI] isci: over...
117
  unsigned char max_concurr_spinup;
b5f18a201   Dave Jiang   isci: exposing us...
118
119
  module_param(max_concurr_spinup, byte, 0);
  MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup");
3a7bda830   Dave Jiang   [SCSI] isci: Addi...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf)
  {
  	struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev);
  	struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
  	struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha);
  
  	return snprintf(buf, PAGE_SIZE, "%d
  ", ihost->id);
  }
  
  static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL);
  
  struct device_attribute *isci_host_attrs[] = {
  	&dev_attr_isci_id,
  	NULL
  };
6f231dda6   Dan Williams   isci: Intel(R) C6...
136
137
138
139
  static struct scsi_host_template isci_sht = {
  
  	.module				= THIS_MODULE,
  	.name				= DRV_NAME,
92cd51153   Havard Skinnemoen   isci: Initialize ...
140
  	.proc_name			= DRV_NAME,
6f231dda6   Dan Williams   isci: Intel(R) C6...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  	.queuecommand			= sas_queuecommand,
  	.target_alloc			= sas_target_alloc,
  	.slave_configure		= sas_slave_configure,
  	.slave_destroy			= sas_slave_destroy,
  	.scan_finished			= isci_host_scan_finished,
  	.scan_start			= isci_host_scan_start,
  	.change_queue_depth		= sas_change_queue_depth,
  	.change_queue_type		= sas_change_queue_type,
  	.bios_param			= sas_bios_param,
  	.can_queue			= ISCI_CAN_QUEUE_VAL,
  	.cmd_per_lun			= 1,
  	.this_id			= -1,
  	.sg_tablesize			= SG_ALL,
  	.max_sectors			= SCSI_DEFAULT_MAX_SECTORS,
  	.use_clustering			= ENABLE_CLUSTERING,
  	.eh_device_reset_handler	= sas_eh_device_reset_handler,
  	.eh_bus_reset_handler		= isci_bus_reset_handler,
  	.slave_alloc			= sas_slave_alloc,
  	.target_destroy			= sas_target_destroy,
  	.ioctl				= sas_ioctl,
3a7bda830   Dave Jiang   [SCSI] isci: Addi...
161
  	.shost_attrs			= isci_host_attrs,
6f231dda6   Dan Williams   isci: Intel(R) C6...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  };
  
  static struct sas_domain_function_template isci_transport_ops  = {
  
  	/* The class calls these to notify the LLDD of an event. */
  	.lldd_port_formed	= isci_port_formed,
  	.lldd_port_deformed	= isci_port_deformed,
  
  	/* The class calls these when a device is found or gone. */
  	.lldd_dev_found		= isci_remote_device_found,
  	.lldd_dev_gone		= isci_remote_device_gone,
  
  	.lldd_execute_task	= isci_task_execute_task,
  	/* Task Management Functions. Must be called from process context. */
  	.lldd_abort_task	= isci_task_abort_task,
  	.lldd_abort_task_set	= isci_task_abort_task_set,
  	.lldd_clear_aca		= isci_task_clear_aca,
  	.lldd_clear_task_set	= isci_task_clear_task_set,
  	.lldd_I_T_nexus_reset	= isci_task_I_T_nexus_reset,
  	.lldd_lu_reset		= isci_task_lu_reset,
  	.lldd_query_task	= isci_task_query_task,
  
  	/* Port and Adapter management */
  	.lldd_clear_nexus_port	= isci_task_clear_nexus_port,
  	.lldd_clear_nexus_ha	= isci_task_clear_nexus_ha,
  
  	/* Phy management */
  	.lldd_control_phy	= isci_phy_control,
ad4f4c1de   Dan Williams   [SCSI] isci: init...
190
191
192
  
  	/* GPIO support */
  	.lldd_write_gpio	= isci_gpio_write,
6f231dda6   Dan Williams   isci: Intel(R) C6...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  };
  
  
  /******************************************************************************
  * P R O T E C T E D  M E T H O D S
  ******************************************************************************/
  
  
  
  /**
   * isci_register_sas_ha() - This method initializes various lldd
   *    specific members of the sas_ha struct and calls the libsas
   *    sas_register_ha() function.
   * @isci_host: This parameter specifies the lldd specific wrapper for the
   *    libsas sas_ha struct.
   *
   * This method returns an error code indicating sucess or failure. The user
   * should check for possible memory allocation error return otherwise, a zero
   * indicates success.
   */
  static int isci_register_sas_ha(struct isci_host *isci_host)
  {
  	int i;
  	struct sas_ha_struct *sas_ha = &(isci_host->sas_ha);
  	struct asd_sas_phy **sas_phys;
  	struct asd_sas_port **sas_ports;
  
  	sas_phys = devm_kzalloc(&isci_host->pdev->dev,
  				SCI_MAX_PHYS * sizeof(void *),
  				GFP_KERNEL);
  	if (!sas_phys)
  		return -ENOMEM;
  
  	sas_ports = devm_kzalloc(&isci_host->pdev->dev,
  				 SCI_MAX_PORTS * sizeof(void *),
  				 GFP_KERNEL);
  	if (!sas_ports)
  		return -ENOMEM;
  
  	/*----------------- Libsas Initialization Stuff----------------------
  	 * Set various fields in the sas_ha struct:
  	 */
  
  	sas_ha->sas_ha_name = DRV_NAME;
  	sas_ha->lldd_module = THIS_MODULE;
150fc6fc7   Dan Williams   isci: fix sas add...
238
  	sas_ha->sas_addr    = &isci_host->phys[0].sas_addr[0];
6f231dda6   Dan Williams   isci: Intel(R) C6...
239
240
241
  
  	/* set the array of phy and port structs.  */
  	for (i = 0; i < SCI_MAX_PHYS; i++) {
e531381e2   Dan Williams   isci: unify port ...
242
243
  		sas_phys[i] = &isci_host->phys[i].sas_phy;
  		sas_ports[i] = &isci_host->ports[i].sas_port;
6f231dda6   Dan Williams   isci: Intel(R) C6...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  	}
  
  	sas_ha->sas_phy  = sas_phys;
  	sas_ha->sas_port = sas_ports;
  	sas_ha->num_phys = SCI_MAX_PHYS;
  
  	sas_ha->lldd_queue_size = ISCI_CAN_QUEUE_VAL;
  	sas_ha->lldd_max_execute_num = 1;
  	sas_ha->strict_wide_ports = 1;
  
  	sas_register_ha(sas_ha);
  
  	return 0;
  }
34cad85d1   Dan Williams   isci: add "isci_i...
258
259
260
  static void isci_unregister(struct isci_host *isci_host)
  {
  	struct Scsi_Host *shost;
6f231dda6   Dan Williams   isci: Intel(R) C6...
261
262
  	if (!isci_host)
  		return;
34cad85d1   Dan Williams   isci: add "isci_i...
263
  	shost = isci_host->shost;
34cad85d1   Dan Williams   isci: add "isci_i...
264
265
  
  	sas_unregister_ha(&isci_host->sas_ha);
6f231dda6   Dan Williams   isci: Intel(R) C6...
266
267
268
269
270
271
272
273
  
  	sas_remove_host(isci_host->shost);
  	scsi_remove_host(isci_host->shost);
  	scsi_host_put(isci_host->shost);
  }
  
  static int __devinit isci_pci_init(struct pci_dev *pdev)
  {
cc3dbd0a9   Artur Wojcik   isci: unify isci_...
274
  	int err, bar_num, bar_mask = 0;
6f231dda6   Dan Williams   isci: Intel(R) C6...
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  	void __iomem * const *iomap;
  
  	err = pcim_enable_device(pdev);
  	if (err) {
  		dev_err(&pdev->dev,
  			"failed enable PCI device %s!
  ",
  			pci_name(pdev));
  		return err;
  	}
  
  	for (bar_num = 0; bar_num < SCI_PCI_BAR_COUNT; bar_num++)
  		bar_mask |= 1 << (bar_num * 2);
  
  	err = pcim_iomap_regions(pdev, bar_mask, DRV_NAME);
  	if (err)
  		return err;
  
  	iomap = pcim_iomap_table(pdev);
  	if (!iomap)
  		return -ENOMEM;
  
  	pci_set_master(pdev);
  
  	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
  	if (err) {
  		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
  		if (err)
  			return err;
  	}
  
  	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
  	if (err) {
  		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
  		if (err)
  			return err;
  	}
  
  	return 0;
  }
6f231dda6   Dan Williams   isci: Intel(R) C6...
315
316
317
318
319
320
321
322
  static int num_controllers(struct pci_dev *pdev)
  {
  	/* bar size alone can tell us if we are running with a dual controller
  	 * part, no need to trust revision ids that might be under broken firmware
  	 * control
  	 */
  	resource_size_t scu_bar_size = pci_resource_len(pdev, SCI_SCU_BAR*2);
  	resource_size_t smu_bar_size = pci_resource_len(pdev, SCI_SMU_BAR*2);
f942f32ea   Dan Williams   isci: reorder ini...
323

6f231dda6   Dan Williams   isci: Intel(R) C6...
324
325
326
327
328
329
330
331
332
333
  	if (scu_bar_size >= SCI_SCU_BAR_SIZE*SCI_MAX_CONTROLLERS &&
  	    smu_bar_size >= SCI_SMU_BAR_SIZE*SCI_MAX_CONTROLLERS)
  		return SCI_MAX_CONTROLLERS;
  	else
  		return 1;
  }
  
  static int isci_setup_interrupts(struct pci_dev *pdev)
  {
  	int err, i, num_msix;
31e824ed0   Dan Williams   isci: rely on irq...
334
  	struct isci_host *ihost;
6f231dda6   Dan Williams   isci: Intel(R) C6...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  	struct isci_pci_info *pci_info = to_pci_info(pdev);
  
  	/*
  	 *  Determine the number of vectors associated with this
  	 *  PCI function.
  	 */
  	num_msix = num_controllers(pdev) * SCI_NUM_MSI_X_INT;
  
  	for (i = 0; i < num_msix; i++)
  		pci_info->msix_entries[i].entry = i;
  
  	err = pci_enable_msix(pdev, pci_info->msix_entries, num_msix);
  	if (err)
  		goto intx;
  
  	for (i = 0; i < num_msix; i++) {
  		int id = i / SCI_NUM_MSI_X_INT;
  		struct msix_entry *msix = &pci_info->msix_entries[i];
92f4f0f54   Dan Williams   isci: implement e...
353
  		irq_handler_t isr;
31e824ed0   Dan Williams   isci: rely on irq...
354
  		ihost = pci_info->hosts[id];
92f4f0f54   Dan Williams   isci: implement e...
355
356
357
358
359
  		/* odd numbered vectors are error interrupts */
  		if (i & 1)
  			isr = isci_error_isr;
  		else
  			isr = isci_msix_isr;
6f231dda6   Dan Williams   isci: Intel(R) C6...
360

92f4f0f54   Dan Williams   isci: implement e...
361
  		err = devm_request_irq(&pdev->dev, msix->vector, isr, 0,
31e824ed0   Dan Williams   isci: rely on irq...
362
  				       DRV_NAME"-msix", ihost);
6f231dda6   Dan Williams   isci: Intel(R) C6...
363
364
365
366
367
368
369
  		if (!err)
  			continue;
  
  		dev_info(&pdev->dev, "msix setup failed falling back to intx
  ");
  		while (i--) {
  			id = i / SCI_NUM_MSI_X_INT;
31e824ed0   Dan Williams   isci: rely on irq...
370
  			ihost = pci_info->hosts[id];
6f231dda6   Dan Williams   isci: Intel(R) C6...
371
  			msix = &pci_info->msix_entries[i];
31e824ed0   Dan Williams   isci: rely on irq...
372
  			devm_free_irq(&pdev->dev, msix->vector, ihost);
6f231dda6   Dan Williams   isci: Intel(R) C6...
373
374
375
376
  		}
  		pci_disable_msix(pdev);
  		goto intx;
  	}
6f231dda6   Dan Williams   isci: Intel(R) C6...
377
378
379
  	return 0;
  
   intx:
31e824ed0   Dan Williams   isci: rely on irq...
380
381
382
383
384
385
  	for_each_isci_host(i, ihost, pdev) {
  		err = devm_request_irq(&pdev->dev, pdev->irq, isci_intx_isr,
  				       IRQF_SHARED, DRV_NAME"-intx", ihost);
  		if (err)
  			break;
  	}
6f231dda6   Dan Williams   isci: Intel(R) C6...
386
387
  	return err;
  }
6f231dda6   Dan Williams   isci: Intel(R) C6...
388
389
390
391
392
  static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
  {
  	struct isci_host *isci_host;
  	struct Scsi_Host *shost;
  	int err;
57f20f4ed   Dan Williams   isci: unify remot...
393
  	isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL);
6f231dda6   Dan Williams   isci: Intel(R) C6...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  	if (!isci_host)
  		return NULL;
  
  	isci_host->pdev = pdev;
  	isci_host->id = id;
  
  	shost = scsi_host_alloc(&isci_sht, sizeof(void *));
  	if (!shost)
  		return NULL;
  	isci_host->shost = shost;
  
  	err = isci_host_init(isci_host);
  	if (err)
  		goto err_shost;
  
  	SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha;
  	isci_host->sas_ha.core.shost = shost;
  	shost->transportt = isci_transport_template;
  
  	shost->max_id = ~0;
  	shost->max_lun = ~0;
  	shost->max_cmd_len = MAX_COMMAND_SIZE;
  
  	err = scsi_add_host(shost, &pdev->dev);
  	if (err)
  		goto err_shost;
  
  	err = isci_register_sas_ha(isci_host);
  	if (err)
  		goto err_shost_remove;
  
  	return isci_host;
  
   err_shost_remove:
  	scsi_remove_host(shost);
   err_shost:
  	scsi_host_put(shost);
  
  	return NULL;
  }
6f231dda6   Dan Williams   isci: Intel(R) C6...
434
435
436
437
438
  static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
  {
  	struct isci_pci_info *pci_info;
  	int err, i;
  	struct isci_host *isci_host;
858d4aa74   Dave Jiang   isci: Move firmwa...
439
  	const struct firmware *fw = NULL;
d37ee7e89   Dan Williams   isci: allow fallb...
440
  	struct isci_orom *orom = NULL;
4711ba10b   Dan Williams   isci: fix oem par...
441
  	char *source = "(platform)";
6f231dda6   Dan Williams   isci: Intel(R) C6...
442

dc00c8b69   Dan Williams   isci: cleanup sil...
443
444
445
  	dev_info(&pdev->dev, "driver configured for rev: %d silicon
  ",
  		 pdev->revision);
6f231dda6   Dan Williams   isci: Intel(R) C6...
446
447
448
449
450
  
  	pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL);
  	if (!pci_info)
  		return -ENOMEM;
  	pci_set_drvdata(pdev, pci_info);
8db37aaba   Dave Jiang   isci: Adding EFI ...
451
452
  	if (efi_enabled)
  		orom = isci_get_efi_var(pdev);
d37ee7e89   Dan Williams   isci: allow fallb...
453
454
  
  	if (!orom)
d044af17a   Dan Williams   isci: Add support...
455
  		orom = isci_request_oprom(pdev);
2d70de5a0   Dan Williams   isci: validate oe...
456
  	for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) {
89a7301f2   Dan Williams   isci: retire scic...
457
  		if (sci_oem_parameters_validate(&orom->ctrl[i])) {
2d70de5a0   Dan Williams   isci: validate oe...
458
459
460
461
462
463
464
465
  			dev_warn(&pdev->dev,
  				 "[%d]: invalid oem parameters detected, falling back to firmware
  ", i);
  			devm_kfree(&pdev->dev, orom);
  			orom = NULL;
  			break;
  		}
  	}
d044af17a   Dan Williams   isci: Add support...
466
  	if (!orom) {
4711ba10b   Dan Williams   isci: fix oem par...
467
  		source = "(firmware)";
d044af17a   Dan Williams   isci: Add support...
468
469
470
471
472
473
474
475
476
477
478
479
480
  		orom = isci_request_firmware(pdev, fw);
  		if (!orom) {
  			/* TODO convert this to WARN_TAINT_ONCE once the
  			 * orom/efi parameter support is widely available
  			 */
  			dev_warn(&pdev->dev,
  				 "Loading user firmware failed, using default "
  				 "values
  ");
  			dev_warn(&pdev->dev,
  				 "Default OEM configuration being used: 4 "
  				 "narrow ports, and default SAS Addresses
  ");
858d4aa74   Dave Jiang   isci: Move firmwa...
481
  		}
858d4aa74   Dave Jiang   isci: Move firmwa...
482
  	}
d044af17a   Dan Williams   isci: Add support...
483
  	if (orom)
3b67c1f37   Dan Williams   isci: fixup with ...
484
  		dev_info(&pdev->dev,
4711ba10b   Dan Williams   isci: fix oem par...
485
486
  			 "OEM SAS parameters (version: %u.%u) loaded %s
  ",
3b67c1f37   Dan Williams   isci: fixup with ...
487
  			 (orom->hdr.version & 0xf0) >> 4,
4711ba10b   Dan Williams   isci: fix oem par...
488
  			 (orom->hdr.version & 0xf), source);
3b67c1f37   Dan Williams   isci: fixup with ...
489

d044af17a   Dan Williams   isci: Add support...
490
  	pci_info->orom = orom;
6f231dda6   Dan Williams   isci: Intel(R) C6...
491
492
493
494
495
496
497
498
499
500
501
  	err = isci_pci_init(pdev);
  	if (err)
  		return err;
  
  	for (i = 0; i < num_controllers(pdev); i++) {
  		struct isci_host *h = isci_host_alloc(pdev, i);
  
  		if (!h) {
  			err = -ENOMEM;
  			goto err_host_alloc;
  		}
b329aff10   Dan Williams   isci: kill isci_h...
502
  		pci_info->hosts[i] = h;
6f231dda6   Dan Williams   isci: Intel(R) C6...
503
504
505
506
507
  	}
  
  	err = isci_setup_interrupts(pdev);
  	if (err)
  		goto err_host_alloc;
b329aff10   Dan Williams   isci: kill isci_h...
508
  	for_each_isci_host(i, isci_host, pdev)
6f231dda6   Dan Williams   isci: Intel(R) C6...
509
510
511
512
513
  		scsi_scan_host(isci_host->shost);
  
  	return 0;
  
   err_host_alloc:
b329aff10   Dan Williams   isci: kill isci_h...
514
  	for_each_isci_host(i, isci_host, pdev)
34cad85d1   Dan Williams   isci: add "isci_i...
515
  		isci_unregister(isci_host);
6f231dda6   Dan Williams   isci: Intel(R) C6...
516
517
518
519
520
  	return err;
  }
  
  static void __devexit isci_pci_remove(struct pci_dev *pdev)
  {
d9dcb4ba7   Dan Williams   isci: unify isci_...
521
  	struct isci_host *ihost;
b329aff10   Dan Williams   isci: kill isci_h...
522
  	int i;
6f231dda6   Dan Williams   isci: Intel(R) C6...
523

d9dcb4ba7   Dan Williams   isci: unify isci_...
524
525
526
  	for_each_isci_host(i, ihost, pdev) {
  		isci_unregister(ihost);
  		isci_host_deinit(ihost);
89a7301f2   Dan Williams   isci: retire scic...
527
  		sci_controller_disable_interrupts(ihost);
6f231dda6   Dan Williams   isci: Intel(R) C6...
528
529
  	}
  }
f942f32ea   Dan Williams   isci: reorder ini...
530
531
532
533
534
535
  static struct pci_driver isci_pci_driver = {
  	.name		= DRV_NAME,
  	.id_table	= isci_id_table,
  	.probe		= isci_pci_probe,
  	.remove		= __devexit_p(isci_pci_remove),
  };
6f231dda6   Dan Williams   isci: Intel(R) C6...
536
537
  static __init int isci_init(void)
  {
d9c37390c   Dan Williams   isci: preallocate...
538
  	int err;
6f231dda6   Dan Williams   isci: Intel(R) C6...
539

98e2a5a3a   Dan Williams   [SCSI] isci: add ...
540
541
542
  	pr_info("%s: Intel(R) C600 SAS Controller Driver - version %s
  ",
  		DRV_NAME, DRV_VERSION);
6f231dda6   Dan Williams   isci: Intel(R) C6...
543

6f231dda6   Dan Williams   isci: Intel(R) C6...
544
545
  	isci_transport_template = sas_domain_attach_transport(&isci_transport_ops);
  	if (!isci_transport_template)
d9c37390c   Dan Williams   isci: preallocate...
546
  		return -ENOMEM;
6f231dda6   Dan Williams   isci: Intel(R) C6...
547
548
549
  
  	err = pci_register_driver(&isci_pci_driver);
  	if (err)
d9c37390c   Dan Williams   isci: preallocate...
550
  		sas_release_transport(isci_transport_template);
6f231dda6   Dan Williams   isci: Intel(R) C6...
551
552
553
554
555
556
557
558
  
  	return err;
  }
  
  static __exit void isci_exit(void)
  {
  	pci_unregister_driver(&isci_pci_driver);
  	sas_release_transport(isci_transport_template);
6f231dda6   Dan Williams   isci: Intel(R) C6...
559
560
561
562
563
564
  }
  
  MODULE_LICENSE("Dual BSD/GPL");
  MODULE_FIRMWARE(ISCI_FW_NAME);
  module_init(isci_init);
  module_exit(isci_exit);