blob: 17e9757e728be780211d1e7a0008aaa9e2724d18 [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
3 * For use with LSI Logic PCI chip/adapter(s)
4 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
6 * Copyright (c) 1999-2005 LSI Logic Corporation
7 * (mailto:mpt_linux_developer@lsil.com)
8 * Copyright (c) 2005 Dell
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
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
51#include <linux/sched.h>
52#include <linux/workqueue.h>
53
54#include <scsi/scsi_cmnd.h>
55#include <scsi/scsi_device.h>
56#include <scsi/scsi_host.h>
57#include <scsi/scsi_transport_sas.h>
58
59#include "mptbase.h"
60#include "mptscsih.h"
61
62
63#define my_NAME "Fusion MPT SAS Host driver"
64#define my_VERSION MPT_LINUX_VERSION_COMMON
65#define MYNAM "mptsas"
66
67MODULE_AUTHOR(MODULEAUTHOR);
68MODULE_DESCRIPTION(my_NAME);
69MODULE_LICENSE("GPL");
70
71static int mpt_pq_filter;
72module_param(mpt_pq_filter, int, 0);
73MODULE_PARM_DESC(mpt_pq_filter,
74 "Enable peripheral qualifier filter: enable=1 "
75 "(default=0)");
76
77static int mpt_pt_clear;
78module_param(mpt_pt_clear, int, 0);
79MODULE_PARM_DESC(mpt_pt_clear,
80 "Clear persistency table: enable=1 "
81 "(default=MPTSCSIH_PT_CLEAR=0)");
82
83static int mptsasDoneCtx = -1;
84static int mptsasTaskCtx = -1;
85static int mptsasInternalCtx = -1; /* Used only for internal commands */
Christoph Hellwigda4fa652005-10-19 20:01:42 +020086static int mptsasMgmtCtx = -1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020087
88
89/*
90 * SAS topology structures
91 *
92 * The MPT Fusion firmware interface spreads information about the
93 * SAS topology over many manufacture pages, thus we need some data
94 * structure to collect it and process it for the SAS transport class.
95 */
96
97struct mptsas_devinfo {
98 u16 handle; /* unique id to address this device */
99 u8 phy_id; /* phy number of parent device */
100 u8 port_id; /* sas physical port this device
101 is assoc'd with */
102 u8 target; /* logical target id of this device */
103 u8 bus; /* logical bus number of this device */
104 u64 sas_address; /* WWN of this device,
105 SATA is assigned by HBA,expander */
106 u32 device_info; /* bitfield detailed info about this device */
107};
108
109struct mptsas_phyinfo {
110 u8 phy_id; /* phy index */
111 u8 port_id; /* port number this phy is part of */
112 u8 negotiated_link_rate; /* nego'd link rate for this phy */
113 u8 hw_link_rate; /* hardware max/min phys link rate */
114 u8 programmed_link_rate; /* programmed max/min phy link rate */
115 struct mptsas_devinfo identify; /* point to phy device info */
116 struct mptsas_devinfo attached; /* point to attached device info */
117 struct sas_rphy *rphy;
118};
119
120struct mptsas_portinfo {
121 struct list_head list;
122 u16 handle; /* unique id to address this */
123 u8 num_phys; /* number of phys */
124 struct mptsas_phyinfo *phy_info;
125};
126
Christoph Hellwigb5141122005-10-28 22:07:41 +0200127
128#ifdef SASDEBUG
129static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
130{
131 printk("---- IO UNIT PAGE 0 ------------\n");
132 printk("Handle=0x%X\n",
133 le16_to_cpu(phy_data->AttachedDeviceHandle));
134 printk("Controller Handle=0x%X\n",
135 le16_to_cpu(phy_data->ControllerDevHandle));
136 printk("Port=0x%X\n", phy_data->Port);
137 printk("Port Flags=0x%X\n", phy_data->PortFlags);
138 printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
139 printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
140 printk("Controller PHY Device Info=0x%X\n",
141 le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
142 printk("DiscoveryStatus=0x%X\n",
143 le32_to_cpu(phy_data->DiscoveryStatus));
144 printk("\n");
145}
146
147static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
148{
149 __le64 sas_address;
150
151 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
152
153 printk("---- SAS PHY PAGE 0 ------------\n");
154 printk("Attached Device Handle=0x%X\n",
155 le16_to_cpu(pg0->AttachedDevHandle));
156 printk("SAS Address=0x%llX\n",
157 (unsigned long long)le64_to_cpu(sas_address));
158 printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
159 printk("Attached Device Info=0x%X\n",
160 le32_to_cpu(pg0->AttachedDeviceInfo));
161 printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
162 printk("Change Count=0x%X\n", pg0->ChangeCount);
163 printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
164 printk("\n");
165}
166
167static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
168{
169 printk("---- SAS PHY PAGE 1 ------------\n");
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200170 printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
171 printk("Running Disparity Error Count=0x%x\n",
Christoph Hellwigb5141122005-10-28 22:07:41 +0200172 pg1->RunningDisparityErrorCount);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200173 printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
174 printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
175 printk("\n");
Christoph Hellwigb5141122005-10-28 22:07:41 +0200176}
177
178static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
179{
180 __le64 sas_address;
181
182 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
183
184 printk("---- SAS DEVICE PAGE 0 ---------\n");
185 printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
186 printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
187 printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
188 printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address));
189 printk("Target ID=0x%X\n", pg0->TargetID);
190 printk("Bus=0x%X\n", pg0->Bus);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200191 /* The PhyNum field specifies the PHY number of the parent
192 * device this device is linked to
193 */
194 printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
195 printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200196 printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
197 printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
198 printk("Physical Port=0x%X\n", pg0->PhysicalPort);
199 printk("\n");
200}
201
202static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
203{
204 printk("---- SAS EXPANDER PAGE 1 ------------\n");
205
206 printk("Physical Port=0x%X\n", pg1->PhysicalPort);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200207 printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
Christoph Hellwigb5141122005-10-28 22:07:41 +0200208 printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
209 printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
210 printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
211 printk("Owner Device Handle=0x%X\n",
212 le16_to_cpu(pg1->OwnerDevHandle));
213 printk("Attached Device Handle=0x%X\n",
214 le16_to_cpu(pg1->AttachedDevHandle));
215}
216#else
217#define mptsas_print_phy_data(phy_data) do { } while (0)
218#define mptsas_print_phy_pg0(pg0) do { } while (0)
219#define mptsas_print_phy_pg1(pg1) do { } while (0)
220#define mptsas_print_device_pg0(pg0) do { } while (0)
221#define mptsas_print_expander_pg1(pg1) do { } while (0)
222#endif
223
224
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200225/*
226 * This is pretty ugly. We will be able to seriously clean it up
227 * once the DV code in mptscsih goes away and we can properly
228 * implement ->target_alloc.
229 */
230static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700231mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200232{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700233 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200234 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
235 struct sas_rphy *rphy;
236 struct mptsas_portinfo *p;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700237 VirtTarget *vtarget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200238 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700239 struct scsi_target *starget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200240 int i;
241
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200242 vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
243 if (!vdev) {
244 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
245 hd->ioc->name, sizeof(VirtDevice));
246 return -ENOMEM;
247 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200248 memset(vdev, 0, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200249 vdev->ioc_id = hd->ioc->id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700250 sdev->hostdata = vdev;
251 starget = scsi_target(sdev);
252 vtarget = starget->hostdata;
253 vdev->vtarget = vtarget;
254 if (vtarget->num_luns == 0) {
255 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
256 hd->Targets[sdev->id] = vtarget;
257 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200258
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700259 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200260 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
261 for (i = 0; i < p->num_phys; i++) {
262 if (p->phy_info[i].attached.sas_address ==
263 rphy->identify.sas_address) {
264 vdev->target_id =
265 p->phy_info[i].attached.target;
266 vdev->bus_id = p->phy_info[i].attached.bus;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700267 vdev->lun = sdev->lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200268 goto out;
269 }
270 }
271 }
272
273 printk("No matching SAS device found!!\n");
274 kfree(vdev);
275 return -ENODEV;
276
277 out:
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700278 vtarget->ioc_id = vdev->ioc_id;
279 vtarget->target_id = vdev->target_id;
280 vtarget->bus_id = vdev->bus_id;
281 vtarget->num_luns++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200282 return 0;
283}
284
285static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700286 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200287 .proc_name = "mptsas",
288 .proc_info = mptscsih_proc_info,
289 .name = "MPT SPI Host",
290 .info = mptscsih_info,
291 .queuecommand = mptscsih_qcmd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700292 .target_alloc = mptscsih_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200293 .slave_alloc = mptsas_slave_alloc,
294 .slave_configure = mptscsih_slave_configure,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700295 .target_destroy = mptscsih_target_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200296 .slave_destroy = mptscsih_slave_destroy,
297 .change_queue_depth = mptscsih_change_queue_depth,
298 .eh_abort_handler = mptscsih_abort,
299 .eh_device_reset_handler = mptscsih_dev_reset,
300 .eh_bus_reset_handler = mptscsih_bus_reset,
301 .eh_host_reset_handler = mptscsih_host_reset,
302 .bios_param = mptscsih_bios_param,
303 .can_queue = MPT_FC_CAN_QUEUE,
304 .this_id = -1,
305 .sg_tablesize = MPT_SCSI_SG_DEPTH,
306 .max_sectors = 8192,
307 .cmd_per_lun = 7,
308 .use_clustering = ENABLE_CLUSTERING,
309};
310
Christoph Hellwigb5141122005-10-28 22:07:41 +0200311static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
312{
313 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
314 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
315}
316
317static int mptsas_get_linkerrors(struct sas_phy *phy)
318{
319 MPT_ADAPTER *ioc = phy_to_ioc(phy);
320 ConfigExtendedPageHeader_t hdr;
321 CONFIGPARMS cfg;
322 SasPhyPage1_t *buffer;
323 dma_addr_t dma_handle;
324 int error;
325
326 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
327 hdr.ExtPageLength = 0;
328 hdr.PageNumber = 1 /* page number 1*/;
329 hdr.Reserved1 = 0;
330 hdr.Reserved2 = 0;
331 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
332 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
333
334 cfg.cfghdr.ehdr = &hdr;
335 cfg.physAddr = -1;
336 cfg.pageAddr = phy->identify.phy_identifier;
337 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
338 cfg.dir = 0; /* read */
339 cfg.timeout = 10;
340
341 error = mpt_config(ioc, &cfg);
342 if (error)
343 return error;
344 if (!hdr.ExtPageLength)
345 return -ENXIO;
346
347 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
348 &dma_handle);
349 if (!buffer)
350 return -ENOMEM;
351
352 cfg.physAddr = dma_handle;
353 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
354
355 error = mpt_config(ioc, &cfg);
356 if (error)
357 goto out_free_consistent;
358
359 mptsas_print_phy_pg1(buffer);
360
361 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
362 phy->running_disparity_error_count =
363 le32_to_cpu(buffer->RunningDisparityErrorCount);
364 phy->loss_of_dword_sync_count =
365 le32_to_cpu(buffer->LossDwordSynchCount);
366 phy->phy_reset_problem_count =
367 le32_to_cpu(buffer->PhyResetProblemCount);
368
369 out_free_consistent:
370 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
371 buffer, dma_handle);
372 return error;
373}
374
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200375static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
376 MPT_FRAME_HDR *reply)
377{
378 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
379 if (reply != NULL) {
380 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
381 memcpy(ioc->sas_mgmt.reply, reply,
382 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
383 }
384 complete(&ioc->sas_mgmt.done);
385 return 1;
386}
387
388static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
389{
390 MPT_ADAPTER *ioc = phy_to_ioc(phy);
391 SasIoUnitControlRequest_t *req;
392 SasIoUnitControlReply_t *reply;
393 MPT_FRAME_HDR *mf;
394 MPIHeader_t *hdr;
395 unsigned long timeleft;
396 int error = -ERESTARTSYS;
397
398 /* not implemented for expanders */
399 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
400 return -ENXIO;
401
402 if (down_interruptible(&ioc->sas_mgmt.mutex))
403 goto out;
404
405 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
406 if (!mf) {
407 error = -ENOMEM;
408 goto out_unlock;
409 }
410
411 hdr = (MPIHeader_t *) mf;
412 req = (SasIoUnitControlRequest_t *)mf;
413 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
414 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
415 req->MsgContext = hdr->MsgContext;
416 req->Operation = hard_reset ?
417 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
418 req->PhyNum = phy->identify.phy_identifier;
419
420 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
421
422 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
423 10 * HZ);
424 if (!timeleft) {
425 /* On timeout reset the board */
426 mpt_free_msg_frame(ioc, mf);
427 mpt_HardResetHandler(ioc, CAN_SLEEP);
428 error = -ETIMEDOUT;
429 goto out_unlock;
430 }
431
432 /* a reply frame is expected */
433 if ((ioc->sas_mgmt.status &
434 MPT_IOCTL_STATUS_RF_VALID) == 0) {
435 error = -ENXIO;
436 goto out_unlock;
437 }
438
439 /* process the completed Reply Message Frame */
440 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
441 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
442 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
443 __FUNCTION__,
444 reply->IOCStatus,
445 reply->IOCLogInfo);
446 error = -ENXIO;
447 goto out_unlock;
448 }
449
450 error = 0;
451
452 out_unlock:
453 up(&ioc->sas_mgmt.mutex);
454 out:
455 return error;
456}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200457
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200458static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +0200459 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200460 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200461};
462
463static struct scsi_transport_template *mptsas_transport_template;
464
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200465static int
466mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
467{
468 ConfigExtendedPageHeader_t hdr;
469 CONFIGPARMS cfg;
470 SasIOUnitPage0_t *buffer;
471 dma_addr_t dma_handle;
472 int error, i;
473
474 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
475 hdr.ExtPageLength = 0;
476 hdr.PageNumber = 0;
477 hdr.Reserved1 = 0;
478 hdr.Reserved2 = 0;
479 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
480 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
481
482 cfg.cfghdr.ehdr = &hdr;
483 cfg.physAddr = -1;
484 cfg.pageAddr = 0;
485 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
486 cfg.dir = 0; /* read */
487 cfg.timeout = 10;
488
489 error = mpt_config(ioc, &cfg);
490 if (error)
491 goto out;
492 if (!hdr.ExtPageLength) {
493 error = -ENXIO;
494 goto out;
495 }
496
497 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
498 &dma_handle);
499 if (!buffer) {
500 error = -ENOMEM;
501 goto out;
502 }
503
504 cfg.physAddr = dma_handle;
505 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
506
507 error = mpt_config(ioc, &cfg);
508 if (error)
509 goto out_free_consistent;
510
511 port_info->num_phys = buffer->NumPhys;
512 port_info->phy_info = kcalloc(port_info->num_phys,
513 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
514 if (!port_info->phy_info) {
515 error = -ENOMEM;
516 goto out_free_consistent;
517 }
518
519 for (i = 0; i < port_info->num_phys; i++) {
520 mptsas_print_phy_data(&buffer->PhyData[i]);
521 port_info->phy_info[i].phy_id = i;
522 port_info->phy_info[i].port_id =
523 buffer->PhyData[i].Port;
524 port_info->phy_info[i].negotiated_link_rate =
525 buffer->PhyData[i].NegotiatedLinkRate;
526 }
527
528 out_free_consistent:
529 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
530 buffer, dma_handle);
531 out:
532 return error;
533}
534
535static int
536mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
537 u32 form, u32 form_specific)
538{
539 ConfigExtendedPageHeader_t hdr;
540 CONFIGPARMS cfg;
541 SasPhyPage0_t *buffer;
542 dma_addr_t dma_handle;
543 int error;
544
545 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
546 hdr.ExtPageLength = 0;
547 hdr.PageNumber = 0;
548 hdr.Reserved1 = 0;
549 hdr.Reserved2 = 0;
550 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
551 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
552
553 cfg.cfghdr.ehdr = &hdr;
554 cfg.dir = 0; /* read */
555 cfg.timeout = 10;
556
557 /* Get Phy Pg 0 for each Phy. */
558 cfg.physAddr = -1;
559 cfg.pageAddr = form + form_specific;
560 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
561
562 error = mpt_config(ioc, &cfg);
563 if (error)
564 goto out;
565
566 if (!hdr.ExtPageLength) {
567 error = -ENXIO;
568 goto out;
569 }
570
571 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
572 &dma_handle);
573 if (!buffer) {
574 error = -ENOMEM;
575 goto out;
576 }
577
578 cfg.physAddr = dma_handle;
579 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
580
581 error = mpt_config(ioc, &cfg);
582 if (error)
583 goto out_free_consistent;
584
585 mptsas_print_phy_pg0(buffer);
586
587 phy_info->hw_link_rate = buffer->HwLinkRate;
588 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
589 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
590 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
591
592 out_free_consistent:
593 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
594 buffer, dma_handle);
595 out:
596 return error;
597}
598
599static int
600mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
601 u32 form, u32 form_specific)
602{
603 ConfigExtendedPageHeader_t hdr;
604 CONFIGPARMS cfg;
605 SasDevicePage0_t *buffer;
606 dma_addr_t dma_handle;
607 __le64 sas_address;
608 int error;
609
610 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
611 hdr.ExtPageLength = 0;
612 hdr.PageNumber = 0;
613 hdr.Reserved1 = 0;
614 hdr.Reserved2 = 0;
615 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
616 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
617
618 cfg.cfghdr.ehdr = &hdr;
619 cfg.pageAddr = form + form_specific;
620 cfg.physAddr = -1;
621 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
622 cfg.dir = 0; /* read */
623 cfg.timeout = 10;
624
625 error = mpt_config(ioc, &cfg);
626 if (error)
627 goto out;
628 if (!hdr.ExtPageLength) {
629 error = -ENXIO;
630 goto out;
631 }
632
633 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
634 &dma_handle);
635 if (!buffer) {
636 error = -ENOMEM;
637 goto out;
638 }
639
640 cfg.physAddr = dma_handle;
641 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
642
643 error = mpt_config(ioc, &cfg);
644 if (error)
645 goto out_free_consistent;
646
647 mptsas_print_device_pg0(buffer);
648
649 device_info->handle = le16_to_cpu(buffer->DevHandle);
650 device_info->phy_id = buffer->PhyNum;
651 device_info->port_id = buffer->PhysicalPort;
652 device_info->target = buffer->TargetID;
653 device_info->bus = buffer->Bus;
654 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
655 device_info->sas_address = le64_to_cpu(sas_address);
656 device_info->device_info =
657 le32_to_cpu(buffer->DeviceInfo);
658
659 out_free_consistent:
660 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
661 buffer, dma_handle);
662 out:
663 return error;
664}
665
666static int
667mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
668 u32 form, u32 form_specific)
669{
670 ConfigExtendedPageHeader_t hdr;
671 CONFIGPARMS cfg;
672 SasExpanderPage0_t *buffer;
673 dma_addr_t dma_handle;
674 int error;
675
676 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
677 hdr.ExtPageLength = 0;
678 hdr.PageNumber = 0;
679 hdr.Reserved1 = 0;
680 hdr.Reserved2 = 0;
681 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
682 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
683
684 cfg.cfghdr.ehdr = &hdr;
685 cfg.physAddr = -1;
686 cfg.pageAddr = form + form_specific;
687 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
688 cfg.dir = 0; /* read */
689 cfg.timeout = 10;
690
691 error = mpt_config(ioc, &cfg);
692 if (error)
693 goto out;
694
695 if (!hdr.ExtPageLength) {
696 error = -ENXIO;
697 goto out;
698 }
699
700 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
701 &dma_handle);
702 if (!buffer) {
703 error = -ENOMEM;
704 goto out;
705 }
706
707 cfg.physAddr = dma_handle;
708 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
709
710 error = mpt_config(ioc, &cfg);
711 if (error)
712 goto out_free_consistent;
713
714 /* save config data */
715 port_info->num_phys = buffer->NumPhys;
716 port_info->handle = le16_to_cpu(buffer->DevHandle);
717 port_info->phy_info = kcalloc(port_info->num_phys,
718 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
719 if (!port_info->phy_info) {
720 error = -ENOMEM;
721 goto out_free_consistent;
722 }
723
724 out_free_consistent:
725 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
726 buffer, dma_handle);
727 out:
728 return error;
729}
730
731static int
732mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
733 u32 form, u32 form_specific)
734{
735 ConfigExtendedPageHeader_t hdr;
736 CONFIGPARMS cfg;
737 SasExpanderPage1_t *buffer;
738 dma_addr_t dma_handle;
739 int error;
740
741 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
742 hdr.ExtPageLength = 0;
743 hdr.PageNumber = 1;
744 hdr.Reserved1 = 0;
745 hdr.Reserved2 = 0;
746 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
747 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
748
749 cfg.cfghdr.ehdr = &hdr;
750 cfg.physAddr = -1;
751 cfg.pageAddr = form + form_specific;
752 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
753 cfg.dir = 0; /* read */
754 cfg.timeout = 10;
755
756 error = mpt_config(ioc, &cfg);
757 if (error)
758 goto out;
759
760 if (!hdr.ExtPageLength) {
761 error = -ENXIO;
762 goto out;
763 }
764
765 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
766 &dma_handle);
767 if (!buffer) {
768 error = -ENOMEM;
769 goto out;
770 }
771
772 cfg.physAddr = dma_handle;
773 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
774
775 error = mpt_config(ioc, &cfg);
776 if (error)
777 goto out_free_consistent;
778
779
780 mptsas_print_expander_pg1(buffer);
781
782 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +0200783 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200784 phy_info->port_id = buffer->PhysicalPort;
785 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
786 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
787 phy_info->hw_link_rate = buffer->HwLinkRate;
788 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
789 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
790
791
792 out_free_consistent:
793 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
794 buffer, dma_handle);
795 out:
796 return error;
797}
798
799static void
800mptsas_parse_device_info(struct sas_identify *identify,
801 struct mptsas_devinfo *device_info)
802{
803 u16 protocols;
804
805 identify->sas_address = device_info->sas_address;
806 identify->phy_identifier = device_info->phy_id;
807
808 /*
809 * Fill in Phy Initiator Port Protocol.
810 * Bits 6:3, more than one bit can be set, fall through cases.
811 */
812 protocols = device_info->device_info & 0x78;
813 identify->initiator_port_protocols = 0;
814 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
815 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
816 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
817 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
818 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
819 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
820 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
821 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
822
823 /*
824 * Fill in Phy Target Port Protocol.
825 * Bits 10:7, more than one bit can be set, fall through cases.
826 */
827 protocols = device_info->device_info & 0x780;
828 identify->target_port_protocols = 0;
829 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
830 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
831 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
832 identify->target_port_protocols |= SAS_PROTOCOL_STP;
833 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
834 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
835 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
836 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
837
838 /*
839 * Fill in Attached device type.
840 */
841 switch (device_info->device_info &
842 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
843 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
844 identify->device_type = SAS_PHY_UNUSED;
845 break;
846 case MPI_SAS_DEVICE_INFO_END_DEVICE:
847 identify->device_type = SAS_END_DEVICE;
848 break;
849 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
850 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
851 break;
852 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
853 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
854 break;
855 }
856}
857
858static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +0200859 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200860{
861 struct sas_phy *port;
862 int error;
863
864 port = sas_phy_alloc(dev, index);
865 if (!port)
866 return -ENOMEM;
867
868 port->port_identifier = phy_info->port_id;
869 mptsas_parse_device_info(&port->identify, &phy_info->identify);
870
871 /*
872 * Set Negotiated link rate.
873 */
874 switch (phy_info->negotiated_link_rate) {
875 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
876 port->negotiated_linkrate = SAS_PHY_DISABLED;
877 break;
878 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
879 port->negotiated_linkrate = SAS_LINK_RATE_FAILED;
880 break;
881 case MPI_SAS_IOUNIT0_RATE_1_5:
882 port->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
883 break;
884 case MPI_SAS_IOUNIT0_RATE_3_0:
885 port->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
886 break;
887 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
888 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
889 default:
890 port->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
891 break;
892 }
893
894 /*
895 * Set Max hardware link rate.
896 */
897 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
898 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
899 port->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
900 break;
901 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
902 port->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
903 break;
904 default:
905 break;
906 }
907
908 /*
909 * Set Max programmed link rate.
910 */
911 switch (phy_info->programmed_link_rate &
912 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
913 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
914 port->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
915 break;
916 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
917 port->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
918 break;
919 default:
920 break;
921 }
922
923 /*
924 * Set Min hardware link rate.
925 */
926 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
927 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
928 port->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
929 break;
930 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
931 port->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
932 break;
933 default:
934 break;
935 }
936
937 /*
938 * Set Min programmed link rate.
939 */
940 switch (phy_info->programmed_link_rate &
941 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
942 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
943 port->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
944 break;
945 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
946 port->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
947 break;
948 default:
949 break;
950 }
951
Christoph Hellwigac01bbb2005-10-19 20:01:17 +0200952 if (local)
953 port->local_attached = 1;
954
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200955 error = sas_phy_add(port);
956 if (error) {
957 sas_phy_free(port);
958 return error;
959 }
960
961 if (phy_info->attached.handle) {
962 struct sas_rphy *rphy;
963
964 rphy = sas_rphy_alloc(port);
965 if (!rphy)
966 return 0; /* non-fatal: an rphy can be added later */
967
968 mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
969 error = sas_rphy_add(rphy);
970 if (error) {
971 sas_rphy_free(rphy);
972 return error;
973 }
974
975 phy_info->rphy = rphy;
976 }
977
978 return 0;
979}
980
981static int
982mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index)
983{
984 struct mptsas_portinfo *port_info;
985 u32 handle = 0xFFFF;
986 int error = -ENOMEM, i;
987
988 port_info = kmalloc(sizeof(*port_info), GFP_KERNEL);
989 if (!port_info)
990 goto out;
991 memset(port_info, 0, sizeof(*port_info));
992
993 error = mptsas_sas_io_unit_pg0(ioc, port_info);
994 if (error)
995 goto out_free_port_info;
996
997 list_add_tail(&port_info->list, &ioc->sas_topology);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200998 for (i = 0; i < port_info->num_phys; i++) {
999 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
1000 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
1001 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
1002
1003 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
1004 (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE <<
1005 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle);
Eric Moore024358e2005-10-21 20:56:36 +02001006 port_info->phy_info[i].identify.phy_id =
1007 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001008 handle = port_info->phy_info[i].identify.handle;
1009
1010 if (port_info->phy_info[i].attached.handle) {
1011 mptsas_sas_device_pg0(ioc,
1012 &port_info->phy_info[i].attached,
1013 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1014 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1015 port_info->phy_info[i].attached.handle);
1016 }
1017
1018 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001019 &port_info->phy_info[i], *index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001020 (*index)++;
1021 }
1022
1023 return 0;
1024
1025 out_free_port_info:
1026 kfree(port_info);
1027 out:
1028 return error;
1029}
1030
1031static int
1032mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index)
1033{
1034 struct mptsas_portinfo *port_info, *p;
1035 int error = -ENOMEM, i, j;
1036
1037 port_info = kmalloc(sizeof(*port_info), GFP_KERNEL);
1038 if (!port_info)
1039 goto out;
1040 memset(port_info, 0, sizeof(*port_info));
1041
1042 error = mptsas_sas_expander_pg0(ioc, port_info,
1043 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
1044 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
1045 if (error)
1046 goto out_free_port_info;
1047
1048 *handle = port_info->handle;
1049
1050 list_add_tail(&port_info->list, &ioc->sas_topology);
1051 for (i = 0; i < port_info->num_phys; i++) {
1052 struct device *parent;
1053
1054 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
1055 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
1056 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
1057
1058 if (port_info->phy_info[i].identify.handle) {
1059 mptsas_sas_device_pg0(ioc,
1060 &port_info->phy_info[i].identify,
1061 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1062 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1063 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02001064 port_info->phy_info[i].identify.phy_id =
1065 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001066 }
1067
1068 if (port_info->phy_info[i].attached.handle) {
1069 mptsas_sas_device_pg0(ioc,
1070 &port_info->phy_info[i].attached,
1071 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1072 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1073 port_info->phy_info[i].attached.handle);
1074 }
1075
1076 /*
1077 * If we find a parent port handle this expander is
1078 * attached to another expander, else it hangs of the
1079 * HBA phys.
1080 */
1081 parent = &ioc->sh->shost_gendev;
1082 list_for_each_entry(p, &ioc->sas_topology, list) {
1083 for (j = 0; j < p->num_phys; j++) {
1084 if (port_info->phy_info[i].identify.handle ==
1085 p->phy_info[j].attached.handle)
1086 parent = &p->phy_info[j].rphy->dev;
1087 }
1088 }
1089
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001090 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
1091 *index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001092 (*index)++;
1093 }
1094
1095 return 0;
1096
1097 out_free_port_info:
1098 kfree(port_info);
1099 out:
1100 return error;
1101}
1102
1103static void
1104mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
1105{
1106 u32 handle = 0xFFFF;
1107 int index = 0;
1108
1109 mptsas_probe_hba_phys(ioc, &index);
1110 while (!mptsas_probe_expander_phys(ioc, &handle, &index))
1111 ;
1112}
1113
1114static int
1115mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1116{
1117 struct Scsi_Host *sh;
1118 MPT_SCSI_HOST *hd;
1119 MPT_ADAPTER *ioc;
1120 unsigned long flags;
1121 int sz, ii;
1122 int numSGE = 0;
1123 int scale;
1124 int ioc_cap;
1125 u8 *mem;
1126 int error=0;
1127 int r;
1128
1129 r = mpt_attach(pdev,id);
1130 if (r)
1131 return r;
1132
1133 ioc = pci_get_drvdata(pdev);
1134 ioc->DoneCtx = mptsasDoneCtx;
1135 ioc->TaskCtx = mptsasTaskCtx;
1136 ioc->InternalCtx = mptsasInternalCtx;
1137
1138 /* Added sanity check on readiness of the MPT adapter.
1139 */
1140 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1141 printk(MYIOC_s_WARN_FMT
1142 "Skipping because it's not operational!\n",
1143 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001144 error = -ENODEV;
1145 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001146 }
1147
1148 if (!ioc->active) {
1149 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1150 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001151 error = -ENODEV;
1152 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001153 }
1154
1155 /* Sanity check - ensure at least 1 port is INITIATOR capable
1156 */
1157 ioc_cap = 0;
1158 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
1159 if (ioc->pfacts[ii].ProtocolFlags &
1160 MPI_PORTFACTS_PROTOCOL_INITIATOR)
1161 ioc_cap++;
1162 }
1163
1164 if (!ioc_cap) {
1165 printk(MYIOC_s_WARN_FMT
1166 "Skipping ioc=%p because SCSI Initiator mode "
1167 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001168 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001169 }
1170
1171 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
1172 if (!sh) {
1173 printk(MYIOC_s_WARN_FMT
1174 "Unable to register controller with SCSI subsystem\n",
1175 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001176 error = -1;
1177 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001178 }
1179
1180 spin_lock_irqsave(&ioc->FreeQlock, flags);
1181
1182 /* Attach the SCSI Host to the IOC structure
1183 */
1184 ioc->sh = sh;
1185
1186 sh->io_port = 0;
1187 sh->n_io_port = 0;
1188 sh->irq = 0;
1189
1190 /* set 16 byte cdb's */
1191 sh->max_cmd_len = 16;
1192
1193 sh->max_id = ioc->pfacts->MaxDevices + 1;
1194
1195 sh->transportt = mptsas_transport_template;
1196
1197 sh->max_lun = MPT_LAST_LUN + 1;
1198 sh->max_channel = 0;
1199 sh->this_id = ioc->pfacts[0].PortSCSIID;
1200
1201 /* Required entry.
1202 */
1203 sh->unique_id = ioc->id;
1204
1205 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001206 init_MUTEX(&ioc->sas_mgmt.mutex);
1207 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001208
1209 /* Verify that we won't exceed the maximum
1210 * number of chain buffers
1211 * We can optimize: ZZ = req_sz/sizeof(SGE)
1212 * For 32bit SGE's:
1213 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1214 * + (req_sz - 64)/sizeof(SGE)
1215 * A slightly different algorithm is required for
1216 * 64bit SGEs.
1217 */
1218 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
1219 if (sizeof(dma_addr_t) == sizeof(u64)) {
1220 numSGE = (scale - 1) *
1221 (ioc->facts.MaxChainDepth-1) + scale +
1222 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
1223 sizeof(u32));
1224 } else {
1225 numSGE = 1 + (scale - 1) *
1226 (ioc->facts.MaxChainDepth-1) + scale +
1227 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
1228 sizeof(u32));
1229 }
1230
1231 if (numSGE < sh->sg_tablesize) {
1232 /* Reset this value */
1233 dprintk((MYIOC_s_INFO_FMT
1234 "Resetting sg_tablesize to %d from %d\n",
1235 ioc->name, numSGE, sh->sg_tablesize));
1236 sh->sg_tablesize = numSGE;
1237 }
1238
1239 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1240
1241 hd = (MPT_SCSI_HOST *) sh->hostdata;
1242 hd->ioc = ioc;
1243
1244 /* SCSI needs scsi_cmnd lookup table!
1245 * (with size equal to req_depth*PtrSz!)
1246 */
1247 sz = ioc->req_depth * sizeof(void *);
1248 mem = kmalloc(sz, GFP_ATOMIC);
1249 if (mem == NULL) {
1250 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001251 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001252 }
1253
1254 memset(mem, 0, sz);
1255 hd->ScsiLookup = (struct scsi_cmnd **) mem;
1256
1257 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
1258 ioc->name, hd->ScsiLookup, sz));
1259
1260 /* Allocate memory for the device structures.
1261 * A non-Null pointer at an offset
1262 * indicates a device exists.
1263 * max_id = 1 + maximum id (hosts.h)
1264 */
1265 sz = sh->max_id * sizeof(void *);
1266 mem = kmalloc(sz, GFP_ATOMIC);
1267 if (mem == NULL) {
1268 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001269 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001270 }
1271
1272 memset(mem, 0, sz);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001273 hd->Targets = (VirtTarget **) mem;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001274
1275 dprintk((KERN_INFO
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001276 " vtarget @ %p, sz=%d\n", hd->Targets, sz));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001277
1278 /* Clear the TM flags
1279 */
1280 hd->tmPending = 0;
1281 hd->tmState = TM_STATE_NONE;
1282 hd->resetPending = 0;
1283 hd->abortSCpnt = NULL;
1284
1285 /* Clear the pointer used to store
1286 * single-threaded commands, i.e., those
1287 * issued during a bus scan, dv and
1288 * configuration pages.
1289 */
1290 hd->cmdPtr = NULL;
1291
1292 /* Initialize this SCSI Hosts' timers
1293 * To use, set the timer expires field
1294 * and add_timer
1295 */
1296 init_timer(&hd->timer);
1297 hd->timer.data = (unsigned long) hd;
1298 hd->timer.function = mptscsih_timer_expired;
1299
1300 hd->mpt_pq_filter = mpt_pq_filter;
1301 ioc->sas_data.ptClear = mpt_pt_clear;
1302
1303 if (ioc->sas_data.ptClear==1) {
1304 mptbase_sas_persist_operation(
1305 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
1306 }
1307
1308 ddvprintk((MYIOC_s_INFO_FMT
1309 "mpt_pq_filter %x mpt_pq_filter %x\n",
1310 ioc->name,
1311 mpt_pq_filter,
1312 mpt_pq_filter));
1313
1314 init_waitqueue_head(&hd->scandv_waitq);
1315 hd->scandv_wait_done = 0;
1316 hd->last_queue_full = 0;
1317
1318 error = scsi_add_host(sh, &ioc->pcidev->dev);
1319 if (error) {
1320 dprintk((KERN_ERR MYNAM
1321 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001322 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001323 }
1324
1325 mptsas_scan_sas_topology(ioc);
1326
1327 return 0;
1328
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001329out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001330
1331 mptscsih_remove(pdev);
1332 return error;
1333}
1334
1335static void __devexit mptsas_remove(struct pci_dev *pdev)
1336{
1337 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1338 struct mptsas_portinfo *p, *n;
1339
1340 sas_remove_host(ioc->sh);
1341
1342 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
1343 list_del(&p->list);
1344 kfree(p);
1345 }
1346
1347 mptscsih_remove(pdev);
1348}
1349
1350static struct pci_device_id mptsas_pci_table[] = {
1351 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064,
1352 PCI_ANY_ID, PCI_ANY_ID },
1353 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066,
1354 PCI_ANY_ID, PCI_ANY_ID },
1355 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068,
1356 PCI_ANY_ID, PCI_ANY_ID },
1357 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E,
1358 PCI_ANY_ID, PCI_ANY_ID },
1359 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E,
1360 PCI_ANY_ID, PCI_ANY_ID },
1361 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E,
1362 PCI_ANY_ID, PCI_ANY_ID },
1363 {0} /* Terminating entry */
1364};
1365MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
1366
1367
1368static struct pci_driver mptsas_driver = {
1369 .name = "mptsas",
1370 .id_table = mptsas_pci_table,
1371 .probe = mptsas_probe,
1372 .remove = __devexit_p(mptsas_remove),
1373 .shutdown = mptscsih_shutdown,
1374#ifdef CONFIG_PM
1375 .suspend = mptscsih_suspend,
1376 .resume = mptscsih_resume,
1377#endif
1378};
1379
1380static int __init
1381mptsas_init(void)
1382{
1383 show_mptmod_ver(my_NAME, my_VERSION);
1384
1385 mptsas_transport_template =
1386 sas_attach_transport(&mptsas_transport_functions);
1387 if (!mptsas_transport_template)
1388 return -ENODEV;
1389
1390 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
1391 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
1392 mptsasInternalCtx =
1393 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001394 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001395
1396 if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) {
1397 devtprintk((KERN_INFO MYNAM
1398 ": Registered for IOC event notifications\n"));
1399 }
1400
1401 if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
1402 dprintk((KERN_INFO MYNAM
1403 ": Registered for IOC reset notifications\n"));
1404 }
1405
1406 return pci_register_driver(&mptsas_driver);
1407}
1408
1409static void __exit
1410mptsas_exit(void)
1411{
1412 pci_unregister_driver(&mptsas_driver);
1413 sas_release_transport(mptsas_transport_template);
1414
1415 mpt_reset_deregister(mptsasDoneCtx);
1416 mpt_event_deregister(mptsasDoneCtx);
1417
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001418 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001419 mpt_deregister(mptsasInternalCtx);
1420 mpt_deregister(mptsasTaskCtx);
1421 mpt_deregister(mptsasDoneCtx);
1422}
1423
1424module_init(mptsas_init);
1425module_exit(mptsas_exit);