diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
-rw-r--r-- | drivers/message/fusion/mptsas.c | 818 |
1 files changed, 641 insertions, 177 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 2512d0e6155e..010d4a39269b 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -104,6 +104,13 @@ struct mptsas_hotplug_event { | |||
104 | u16 handle; | 104 | u16 handle; |
105 | u16 parent_handle; | 105 | u16 parent_handle; |
106 | u8 phy_id; | 106 | u8 phy_id; |
107 | u8 phys_disk_num; | ||
108 | u8 phys_disk_num_valid; | ||
109 | }; | ||
110 | |||
111 | struct mptsas_discovery_event { | ||
112 | struct work_struct work; | ||
113 | MPT_ADAPTER *ioc; | ||
107 | }; | 114 | }; |
108 | 115 | ||
109 | /* | 116 | /* |
@@ -117,6 +124,8 @@ struct mptsas_hotplug_event { | |||
117 | struct mptsas_devinfo { | 124 | struct mptsas_devinfo { |
118 | u16 handle; /* unique id to address this device */ | 125 | u16 handle; /* unique id to address this device */ |
119 | u16 handle_parent; /* unique id to address parent device */ | 126 | u16 handle_parent; /* unique id to address parent device */ |
127 | u16 handle_enclosure; /* enclosure identifier of the enclosure */ | ||
128 | u16 slot; /* physical slot in enclosure */ | ||
120 | u8 phy_id; /* phy number of parent device */ | 129 | u8 phy_id; /* phy number of parent device */ |
121 | u8 port_id; /* sas physical port this device | 130 | u8 port_id; /* sas physical port this device |
122 | is assoc'd with */ | 131 | is assoc'd with */ |
@@ -137,6 +146,7 @@ struct mptsas_phyinfo { | |||
137 | struct mptsas_devinfo attached; /* point to attached device info */ | 146 | struct mptsas_devinfo attached; /* point to attached device info */ |
138 | struct sas_phy *phy; | 147 | struct sas_phy *phy; |
139 | struct sas_rphy *rphy; | 148 | struct sas_rphy *rphy; |
149 | struct scsi_target *starget; | ||
140 | }; | 150 | }; |
141 | 151 | ||
142 | struct mptsas_portinfo { | 152 | struct mptsas_portinfo { |
@@ -146,6 +156,17 @@ struct mptsas_portinfo { | |||
146 | struct mptsas_phyinfo *phy_info; | 156 | struct mptsas_phyinfo *phy_info; |
147 | }; | 157 | }; |
148 | 158 | ||
159 | struct mptsas_enclosure { | ||
160 | u64 enclosure_logical_id; /* The WWN for the enclosure */ | ||
161 | u16 enclosure_handle; /* unique id to address this */ | ||
162 | u16 flags; /* details enclosure management */ | ||
163 | u16 num_slot; /* num slots */ | ||
164 | u16 start_slot; /* first slot */ | ||
165 | u8 start_id; /* starting logical target id */ | ||
166 | u8 start_channel; /* starting logical channel id */ | ||
167 | u8 sep_id; /* SEP device logical target id */ | ||
168 | u8 sep_channel; /* SEP channel logical channel id */ | ||
169 | }; | ||
149 | 170 | ||
150 | #ifdef SASDEBUG | 171 | #ifdef SASDEBUG |
151 | static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) | 172 | static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) |
@@ -205,6 +226,7 @@ static void mptsas_print_device_pg0(SasDevicePage0_t *pg0) | |||
205 | 226 | ||
206 | printk("---- SAS DEVICE PAGE 0 ---------\n"); | 227 | printk("---- SAS DEVICE PAGE 0 ---------\n"); |
207 | printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)); | 228 | printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)); |
229 | printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)); | ||
208 | printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)); | 230 | printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)); |
209 | printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot)); | 231 | printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot)); |
210 | printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); | 232 | printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); |
@@ -243,6 +265,111 @@ static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1) | |||
243 | #define mptsas_print_expander_pg1(pg1) do { } while (0) | 265 | #define mptsas_print_expander_pg1(pg1) do { } while (0) |
244 | #endif | 266 | #endif |
245 | 267 | ||
268 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) | ||
269 | { | ||
270 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | ||
271 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
272 | } | ||
273 | |||
274 | static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) | ||
275 | { | ||
276 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); | ||
277 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * mptsas_find_portinfo_by_handle | ||
282 | * | ||
283 | * This function should be called with the sas_topology_mutex already held | ||
284 | */ | ||
285 | static struct mptsas_portinfo * | ||
286 | mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | ||
287 | { | ||
288 | struct mptsas_portinfo *port_info, *rc=NULL; | ||
289 | int i; | ||
290 | |||
291 | list_for_each_entry(port_info, &ioc->sas_topology, list) | ||
292 | for (i = 0; i < port_info->num_phys; i++) | ||
293 | if (port_info->phy_info[i].identify.handle == handle) { | ||
294 | rc = port_info; | ||
295 | goto out; | ||
296 | } | ||
297 | out: | ||
298 | return rc; | ||
299 | } | ||
300 | |||
301 | static int | ||
302 | mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, | ||
303 | u32 form, u32 form_specific) | ||
304 | { | ||
305 | ConfigExtendedPageHeader_t hdr; | ||
306 | CONFIGPARMS cfg; | ||
307 | SasEnclosurePage0_t *buffer; | ||
308 | dma_addr_t dma_handle; | ||
309 | int error; | ||
310 | __le64 le_identifier; | ||
311 | |||
312 | memset(&hdr, 0, sizeof(hdr)); | ||
313 | hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; | ||
314 | hdr.PageNumber = 0; | ||
315 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; | ||
316 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; | ||
317 | |||
318 | cfg.cfghdr.ehdr = &hdr; | ||
319 | cfg.physAddr = -1; | ||
320 | cfg.pageAddr = form + form_specific; | ||
321 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | ||
322 | cfg.dir = 0; /* read */ | ||
323 | cfg.timeout = 10; | ||
324 | |||
325 | error = mpt_config(ioc, &cfg); | ||
326 | if (error) | ||
327 | goto out; | ||
328 | if (!hdr.ExtPageLength) { | ||
329 | error = -ENXIO; | ||
330 | goto out; | ||
331 | } | ||
332 | |||
333 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | ||
334 | &dma_handle); | ||
335 | if (!buffer) { | ||
336 | error = -ENOMEM; | ||
337 | goto out; | ||
338 | } | ||
339 | |||
340 | cfg.physAddr = dma_handle; | ||
341 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | ||
342 | |||
343 | error = mpt_config(ioc, &cfg); | ||
344 | if (error) | ||
345 | goto out_free_consistent; | ||
346 | |||
347 | /* save config data */ | ||
348 | memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64)); | ||
349 | enclosure->enclosure_logical_id = le64_to_cpu(le_identifier); | ||
350 | enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle); | ||
351 | enclosure->flags = le16_to_cpu(buffer->Flags); | ||
352 | enclosure->num_slot = le16_to_cpu(buffer->NumSlots); | ||
353 | enclosure->start_slot = le16_to_cpu(buffer->StartSlot); | ||
354 | enclosure->start_id = buffer->StartTargetID; | ||
355 | enclosure->start_channel = buffer->StartBus; | ||
356 | enclosure->sep_id = buffer->SEPTargetID; | ||
357 | enclosure->sep_channel = buffer->SEPBus; | ||
358 | |||
359 | out_free_consistent: | ||
360 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | ||
361 | buffer, dma_handle); | ||
362 | out: | ||
363 | return error; | ||
364 | } | ||
365 | |||
366 | static int | ||
367 | mptsas_slave_configure(struct scsi_device *sdev) | ||
368 | { | ||
369 | sas_read_port_mode_page(sdev); | ||
370 | |||
371 | return mptscsih_slave_configure(sdev); | ||
372 | } | ||
246 | 373 | ||
247 | /* | 374 | /* |
248 | * This is pretty ugly. We will be able to seriously clean it up | 375 | * This is pretty ugly. We will be able to seriously clean it up |
@@ -259,6 +386,7 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
259 | VirtTarget *vtarget; | 386 | VirtTarget *vtarget; |
260 | VirtDevice *vdev; | 387 | VirtDevice *vdev; |
261 | struct scsi_target *starget; | 388 | struct scsi_target *starget; |
389 | u32 target_id; | ||
262 | int i; | 390 | int i; |
263 | 391 | ||
264 | vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); | 392 | vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); |
@@ -267,10 +395,10 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
267 | hd->ioc->name, sizeof(VirtDevice)); | 395 | hd->ioc->name, sizeof(VirtDevice)); |
268 | return -ENOMEM; | 396 | return -ENOMEM; |
269 | } | 397 | } |
270 | vdev->ioc_id = hd->ioc->id; | ||
271 | sdev->hostdata = vdev; | 398 | sdev->hostdata = vdev; |
272 | starget = scsi_target(sdev); | 399 | starget = scsi_target(sdev); |
273 | vtarget = starget->hostdata; | 400 | vtarget = starget->hostdata; |
401 | vtarget->ioc_id = hd->ioc->id; | ||
274 | vdev->vtarget = vtarget; | 402 | vdev->vtarget = vtarget; |
275 | if (vtarget->num_luns == 0) { | 403 | if (vtarget->num_luns == 0) { |
276 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; | 404 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; |
@@ -281,8 +409,8 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
281 | RAID volumes placed beyond the last expected port. | 409 | RAID volumes placed beyond the last expected port. |
282 | */ | 410 | */ |
283 | if (sdev->channel == hd->ioc->num_ports) { | 411 | if (sdev->channel == hd->ioc->num_ports) { |
284 | vdev->target_id = sdev->id; | 412 | target_id = sdev->id; |
285 | vdev->bus_id = 0; | 413 | vtarget->bus_id = 0; |
286 | vdev->lun = 0; | 414 | vdev->lun = 0; |
287 | goto out; | 415 | goto out; |
288 | } | 416 | } |
@@ -293,11 +421,21 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
293 | for (i = 0; i < p->num_phys; i++) { | 421 | for (i = 0; i < p->num_phys; i++) { |
294 | if (p->phy_info[i].attached.sas_address == | 422 | if (p->phy_info[i].attached.sas_address == |
295 | rphy->identify.sas_address) { | 423 | rphy->identify.sas_address) { |
296 | vdev->target_id = | 424 | target_id = p->phy_info[i].attached.id; |
297 | p->phy_info[i].attached.id; | 425 | vtarget->bus_id = p->phy_info[i].attached.channel; |
298 | vdev->bus_id = p->phy_info[i].attached.channel; | ||
299 | vdev->lun = sdev->lun; | 426 | vdev->lun = sdev->lun; |
300 | mutex_unlock(&hd->ioc->sas_topology_mutex); | 427 | p->phy_info[i].starget = sdev->sdev_target; |
428 | /* | ||
429 | * Exposing hidden disk (RAID) | ||
430 | */ | ||
431 | if (mptscsih_is_phys_disk(hd->ioc, target_id)) { | ||
432 | target_id = mptscsih_raid_id_to_num(hd, | ||
433 | target_id); | ||
434 | vdev->vtarget->tflags |= | ||
435 | MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
436 | sdev->no_uld_attach = 1; | ||
437 | } | ||
438 | mutex_unlock(&hd->ioc->sas_topology_mutex); | ||
301 | goto out; | 439 | goto out; |
302 | } | 440 | } |
303 | } | 441 | } |
@@ -308,9 +446,7 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
308 | return -ENXIO; | 446 | return -ENXIO; |
309 | 447 | ||
310 | out: | 448 | out: |
311 | vtarget->ioc_id = vdev->ioc_id; | 449 | vtarget->target_id = target_id; |
312 | vtarget->target_id = vdev->target_id; | ||
313 | vtarget->bus_id = vdev->bus_id; | ||
314 | vtarget->num_luns++; | 450 | vtarget->num_luns++; |
315 | return 0; | 451 | return 0; |
316 | } | 452 | } |
@@ -320,41 +456,17 @@ mptsas_slave_destroy(struct scsi_device *sdev) | |||
320 | { | 456 | { |
321 | struct Scsi_Host *host = sdev->host; | 457 | struct Scsi_Host *host = sdev->host; |
322 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; | 458 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; |
323 | struct sas_rphy *rphy; | ||
324 | struct mptsas_portinfo *p; | ||
325 | int i; | ||
326 | VirtDevice *vdev; | 459 | VirtDevice *vdev; |
327 | 460 | ||
328 | /* | 461 | /* |
329 | * Handle hotplug removal case. | ||
330 | * We need to clear out attached data structure. | ||
331 | */ | ||
332 | rphy = dev_to_rphy(sdev->sdev_target->dev.parent); | ||
333 | |||
334 | mutex_lock(&hd->ioc->sas_topology_mutex); | ||
335 | list_for_each_entry(p, &hd->ioc->sas_topology, list) { | ||
336 | for (i = 0; i < p->num_phys; i++) { | ||
337 | if (p->phy_info[i].attached.sas_address == | ||
338 | rphy->identify.sas_address) { | ||
339 | memset(&p->phy_info[i].attached, 0, | ||
340 | sizeof(struct mptsas_devinfo)); | ||
341 | p->phy_info[i].rphy = NULL; | ||
342 | goto out; | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | out: | ||
348 | mutex_unlock(&hd->ioc->sas_topology_mutex); | ||
349 | /* | ||
350 | * Issue target reset to flush firmware outstanding commands. | 462 | * Issue target reset to flush firmware outstanding commands. |
351 | */ | 463 | */ |
352 | vdev = sdev->hostdata; | 464 | vdev = sdev->hostdata; |
353 | if (vdev->configured_lun){ | 465 | if (vdev->configured_lun){ |
354 | if (mptscsih_TMHandler(hd, | 466 | if (mptscsih_TMHandler(hd, |
355 | MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, | 467 | MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, |
356 | vdev->bus_id, | 468 | vdev->vtarget->bus_id, |
357 | vdev->target_id, | 469 | vdev->vtarget->target_id, |
358 | 0, 0, 5 /* 5 second timeout */) | 470 | 0, 0, 5 /* 5 second timeout */) |
359 | < 0){ | 471 | < 0){ |
360 | 472 | ||
@@ -364,7 +476,7 @@ mptsas_slave_destroy(struct scsi_device *sdev) | |||
364 | printk(MYIOC_s_WARN_FMT | 476 | printk(MYIOC_s_WARN_FMT |
365 | "Error processing TaskMgmt id=%d TARGET_RESET\n", | 477 | "Error processing TaskMgmt id=%d TARGET_RESET\n", |
366 | hd->ioc->name, | 478 | hd->ioc->name, |
367 | vdev->target_id); | 479 | vdev->vtarget->target_id); |
368 | 480 | ||
369 | hd->tmPending = 0; | 481 | hd->tmPending = 0; |
370 | hd->tmState = TM_STATE_NONE; | 482 | hd->tmState = TM_STATE_NONE; |
@@ -382,7 +494,7 @@ static struct scsi_host_template mptsas_driver_template = { | |||
382 | .queuecommand = mptscsih_qcmd, | 494 | .queuecommand = mptscsih_qcmd, |
383 | .target_alloc = mptscsih_target_alloc, | 495 | .target_alloc = mptscsih_target_alloc, |
384 | .slave_alloc = mptsas_slave_alloc, | 496 | .slave_alloc = mptsas_slave_alloc, |
385 | .slave_configure = mptscsih_slave_configure, | 497 | .slave_configure = mptsas_slave_configure, |
386 | .target_destroy = mptscsih_target_destroy, | 498 | .target_destroy = mptscsih_target_destroy, |
387 | .slave_destroy = mptsas_slave_destroy, | 499 | .slave_destroy = mptsas_slave_destroy, |
388 | .change_queue_depth = mptscsih_change_queue_depth, | 500 | .change_queue_depth = mptscsih_change_queue_depth, |
@@ -399,12 +511,6 @@ static struct scsi_host_template mptsas_driver_template = { | |||
399 | .use_clustering = ENABLE_CLUSTERING, | 511 | .use_clustering = ENABLE_CLUSTERING, |
400 | }; | 512 | }; |
401 | 513 | ||
402 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) | ||
403 | { | ||
404 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | ||
405 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
406 | } | ||
407 | |||
408 | static int mptsas_get_linkerrors(struct sas_phy *phy) | 514 | static int mptsas_get_linkerrors(struct sas_phy *phy) |
409 | { | 515 | { |
410 | MPT_ADAPTER *ioc = phy_to_ioc(phy); | 516 | MPT_ADAPTER *ioc = phy_to_ioc(phy); |
@@ -546,8 +652,67 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
546 | return error; | 652 | return error; |
547 | } | 653 | } |
548 | 654 | ||
655 | static int | ||
656 | mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) | ||
657 | { | ||
658 | MPT_ADAPTER *ioc = rphy_to_ioc(rphy); | ||
659 | int i, error; | ||
660 | struct mptsas_portinfo *p; | ||
661 | struct mptsas_enclosure enclosure_info; | ||
662 | u64 enclosure_handle; | ||
663 | |||
664 | mutex_lock(&ioc->sas_topology_mutex); | ||
665 | list_for_each_entry(p, &ioc->sas_topology, list) { | ||
666 | for (i = 0; i < p->num_phys; i++) { | ||
667 | if (p->phy_info[i].attached.sas_address == | ||
668 | rphy->identify.sas_address) { | ||
669 | enclosure_handle = p->phy_info[i]. | ||
670 | attached.handle_enclosure; | ||
671 | goto found_info; | ||
672 | } | ||
673 | } | ||
674 | } | ||
675 | mutex_unlock(&ioc->sas_topology_mutex); | ||
676 | return -ENXIO; | ||
677 | |||
678 | found_info: | ||
679 | mutex_unlock(&ioc->sas_topology_mutex); | ||
680 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); | ||
681 | error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info, | ||
682 | (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << | ||
683 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle); | ||
684 | if (!error) | ||
685 | *identifier = enclosure_info.enclosure_logical_id; | ||
686 | return error; | ||
687 | } | ||
688 | |||
689 | static int | ||
690 | mptsas_get_bay_identifier(struct sas_rphy *rphy) | ||
691 | { | ||
692 | MPT_ADAPTER *ioc = rphy_to_ioc(rphy); | ||
693 | struct mptsas_portinfo *p; | ||
694 | int i, rc; | ||
695 | |||
696 | mutex_lock(&ioc->sas_topology_mutex); | ||
697 | list_for_each_entry(p, &ioc->sas_topology, list) { | ||
698 | for (i = 0; i < p->num_phys; i++) { | ||
699 | if (p->phy_info[i].attached.sas_address == | ||
700 | rphy->identify.sas_address) { | ||
701 | rc = p->phy_info[i].attached.slot; | ||
702 | goto out; | ||
703 | } | ||
704 | } | ||
705 | } | ||
706 | rc = -ENXIO; | ||
707 | out: | ||
708 | mutex_unlock(&ioc->sas_topology_mutex); | ||
709 | return rc; | ||
710 | } | ||
711 | |||
549 | static struct sas_function_template mptsas_transport_functions = { | 712 | static struct sas_function_template mptsas_transport_functions = { |
550 | .get_linkerrors = mptsas_get_linkerrors, | 713 | .get_linkerrors = mptsas_get_linkerrors, |
714 | .get_enclosure_identifier = mptsas_get_enclosure_identifier, | ||
715 | .get_bay_identifier = mptsas_get_bay_identifier, | ||
551 | .phy_reset = mptsas_phy_reset, | 716 | .phy_reset = mptsas_phy_reset, |
552 | }; | 717 | }; |
553 | 718 | ||
@@ -607,6 +772,9 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) | |||
607 | goto out_free_consistent; | 772 | goto out_free_consistent; |
608 | } | 773 | } |
609 | 774 | ||
775 | if (port_info->num_phys) | ||
776 | port_info->handle = | ||
777 | le16_to_cpu(buffer->PhyData[0].ControllerDevHandle); | ||
610 | for (i = 0; i < port_info->num_phys; i++) { | 778 | for (i = 0; i < port_info->num_phys; i++) { |
611 | mptsas_print_phy_data(&buffer->PhyData[i]); | 779 | mptsas_print_phy_data(&buffer->PhyData[i]); |
612 | port_info->phy_info[i].phy_id = i; | 780 | port_info->phy_info[i].phy_id = i; |
@@ -713,6 +881,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
713 | cfg.dir = 0; /* read */ | 881 | cfg.dir = 0; /* read */ |
714 | cfg.timeout = 10; | 882 | cfg.timeout = 10; |
715 | 883 | ||
884 | memset(device_info, 0, sizeof(struct mptsas_devinfo)); | ||
716 | error = mpt_config(ioc, &cfg); | 885 | error = mpt_config(ioc, &cfg); |
717 | if (error) | 886 | if (error) |
718 | goto out; | 887 | goto out; |
@@ -739,6 +908,9 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
739 | 908 | ||
740 | device_info->handle = le16_to_cpu(buffer->DevHandle); | 909 | device_info->handle = le16_to_cpu(buffer->DevHandle); |
741 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); | 910 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); |
911 | device_info->handle_enclosure = | ||
912 | le16_to_cpu(buffer->EnclosureHandle); | ||
913 | device_info->slot = le16_to_cpu(buffer->Slot); | ||
742 | device_info->phy_id = buffer->PhyNum; | 914 | device_info->phy_id = buffer->PhyNum; |
743 | device_info->port_id = buffer->PhysicalPort; | 915 | device_info->port_id = buffer->PhysicalPort; |
744 | device_info->id = buffer->TargetID; | 916 | device_info->id = buffer->TargetID; |
@@ -780,6 +952,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, | |||
780 | cfg.dir = 0; /* read */ | 952 | cfg.dir = 0; /* read */ |
781 | cfg.timeout = 10; | 953 | cfg.timeout = 10; |
782 | 954 | ||
955 | memset(port_info, 0, sizeof(struct mptsas_portinfo)); | ||
783 | error = mpt_config(ioc, &cfg); | 956 | error = mpt_config(ioc, &cfg); |
784 | if (error) | 957 | if (error) |
785 | goto out; | 958 | goto out; |
@@ -880,7 +1053,6 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, | |||
880 | phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); | 1053 | phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); |
881 | phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); | 1054 | phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); |
882 | 1055 | ||
883 | |||
884 | out_free_consistent: | 1056 | out_free_consistent: |
885 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | 1057 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, |
886 | buffer, dma_handle); | 1058 | buffer, dma_handle); |
@@ -970,12 +1142,19 @@ mptsas_parse_device_info(struct sas_identify *identify, | |||
970 | static int mptsas_probe_one_phy(struct device *dev, | 1142 | static int mptsas_probe_one_phy(struct device *dev, |
971 | struct mptsas_phyinfo *phy_info, int index, int local) | 1143 | struct mptsas_phyinfo *phy_info, int index, int local) |
972 | { | 1144 | { |
1145 | MPT_ADAPTER *ioc; | ||
973 | struct sas_phy *phy; | 1146 | struct sas_phy *phy; |
974 | int error; | 1147 | int error; |
975 | 1148 | ||
976 | phy = sas_phy_alloc(dev, index); | 1149 | if (!dev) |
977 | if (!phy) | 1150 | return -ENODEV; |
978 | return -ENOMEM; | 1151 | |
1152 | if (!phy_info->phy) { | ||
1153 | phy = sas_phy_alloc(dev, index); | ||
1154 | if (!phy) | ||
1155 | return -ENOMEM; | ||
1156 | } else | ||
1157 | phy = phy_info->phy; | ||
979 | 1158 | ||
980 | phy->port_identifier = phy_info->port_id; | 1159 | phy->port_identifier = phy_info->port_id; |
981 | mptsas_parse_device_info(&phy->identify, &phy_info->identify); | 1160 | mptsas_parse_device_info(&phy->identify, &phy_info->identify); |
@@ -1061,24 +1240,54 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
1061 | break; | 1240 | break; |
1062 | } | 1241 | } |
1063 | 1242 | ||
1064 | if (local) | 1243 | if (!phy_info->phy) { |
1065 | phy->local_attached = 1; | ||
1066 | 1244 | ||
1067 | error = sas_phy_add(phy); | 1245 | if (local) |
1068 | if (error) { | 1246 | phy->local_attached = 1; |
1069 | sas_phy_free(phy); | 1247 | |
1070 | return error; | 1248 | error = sas_phy_add(phy); |
1249 | if (error) { | ||
1250 | sas_phy_free(phy); | ||
1251 | return error; | ||
1252 | } | ||
1253 | phy_info->phy = phy; | ||
1071 | } | 1254 | } |
1072 | phy_info->phy = phy; | ||
1073 | 1255 | ||
1074 | if (phy_info->attached.handle) { | 1256 | if ((phy_info->attached.handle) && |
1257 | (!phy_info->rphy)) { | ||
1258 | |||
1075 | struct sas_rphy *rphy; | 1259 | struct sas_rphy *rphy; |
1260 | struct sas_identify identify; | ||
1261 | |||
1262 | ioc = phy_to_ioc(phy_info->phy); | ||
1076 | 1263 | ||
1077 | rphy = sas_rphy_alloc(phy); | 1264 | /* |
1265 | * Let the hotplug_work thread handle processing | ||
1266 | * the adding/removing of devices that occur | ||
1267 | * after start of day. | ||
1268 | */ | ||
1269 | if (ioc->sas_discovery_runtime && | ||
1270 | mptsas_is_end_device(&phy_info->attached)) | ||
1271 | return 0; | ||
1272 | |||
1273 | mptsas_parse_device_info(&identify, &phy_info->attached); | ||
1274 | switch (identify.device_type) { | ||
1275 | case SAS_END_DEVICE: | ||
1276 | rphy = sas_end_device_alloc(phy); | ||
1277 | break; | ||
1278 | case SAS_EDGE_EXPANDER_DEVICE: | ||
1279 | case SAS_FANOUT_EXPANDER_DEVICE: | ||
1280 | rphy = sas_expander_alloc(phy, identify.device_type); | ||
1281 | break; | ||
1282 | default: | ||
1283 | rphy = NULL; | ||
1284 | break; | ||
1285 | } | ||
1078 | if (!rphy) | 1286 | if (!rphy) |
1079 | return 0; /* non-fatal: an rphy can be added later */ | 1287 | return 0; /* non-fatal: an rphy can be added later */ |
1080 | 1288 | ||
1081 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); | 1289 | rphy->identify = identify; |
1290 | |||
1082 | error = sas_rphy_add(rphy); | 1291 | error = sas_rphy_add(rphy); |
1083 | if (error) { | 1292 | if (error) { |
1084 | sas_rphy_free(rphy); | 1293 | sas_rphy_free(rphy); |
@@ -1092,24 +1301,37 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
1092 | } | 1301 | } |
1093 | 1302 | ||
1094 | static int | 1303 | static int |
1095 | mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) | 1304 | mptsas_probe_hba_phys(MPT_ADAPTER *ioc) |
1096 | { | 1305 | { |
1097 | struct mptsas_portinfo *port_info; | 1306 | struct mptsas_portinfo *port_info, *hba; |
1098 | u32 handle = 0xFFFF; | 1307 | u32 handle = 0xFFFF; |
1099 | int error = -ENOMEM, i; | 1308 | int error = -ENOMEM, i; |
1100 | 1309 | ||
1101 | port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); | 1310 | hba = kzalloc(sizeof(*port_info), GFP_KERNEL); |
1102 | if (!port_info) | 1311 | if (! hba) |
1103 | goto out; | 1312 | goto out; |
1104 | 1313 | ||
1105 | error = mptsas_sas_io_unit_pg0(ioc, port_info); | 1314 | error = mptsas_sas_io_unit_pg0(ioc, hba); |
1106 | if (error) | 1315 | if (error) |
1107 | goto out_free_port_info; | 1316 | goto out_free_port_info; |
1108 | 1317 | ||
1109 | ioc->num_ports = port_info->num_phys; | ||
1110 | mutex_lock(&ioc->sas_topology_mutex); | 1318 | mutex_lock(&ioc->sas_topology_mutex); |
1111 | list_add_tail(&port_info->list, &ioc->sas_topology); | 1319 | port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle); |
1320 | if (!port_info) { | ||
1321 | port_info = hba; | ||
1322 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
1323 | } else { | ||
1324 | port_info->handle = hba->handle; | ||
1325 | for (i = 0; i < hba->num_phys; i++) | ||
1326 | port_info->phy_info[i].negotiated_link_rate = | ||
1327 | hba->phy_info[i].negotiated_link_rate; | ||
1328 | if (hba->phy_info) | ||
1329 | kfree(hba->phy_info); | ||
1330 | kfree(hba); | ||
1331 | hba = NULL; | ||
1332 | } | ||
1112 | mutex_unlock(&ioc->sas_topology_mutex); | 1333 | mutex_unlock(&ioc->sas_topology_mutex); |
1334 | ioc->num_ports = port_info->num_phys; | ||
1113 | 1335 | ||
1114 | for (i = 0; i < port_info->num_phys; i++) { | 1336 | for (i = 0; i < port_info->num_phys; i++) { |
1115 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], | 1337 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], |
@@ -1132,38 +1354,49 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) | |||
1132 | } | 1354 | } |
1133 | 1355 | ||
1134 | mptsas_probe_one_phy(&ioc->sh->shost_gendev, | 1356 | mptsas_probe_one_phy(&ioc->sh->shost_gendev, |
1135 | &port_info->phy_info[i], *index, 1); | 1357 | &port_info->phy_info[i], ioc->sas_index, 1); |
1136 | (*index)++; | 1358 | ioc->sas_index++; |
1137 | } | 1359 | } |
1138 | 1360 | ||
1139 | return 0; | 1361 | return 0; |
1140 | 1362 | ||
1141 | out_free_port_info: | 1363 | out_free_port_info: |
1142 | kfree(port_info); | 1364 | if (hba) |
1365 | kfree(hba); | ||
1143 | out: | 1366 | out: |
1144 | return error; | 1367 | return error; |
1145 | } | 1368 | } |
1146 | 1369 | ||
1147 | static int | 1370 | static int |
1148 | mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | 1371 | mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) |
1149 | { | 1372 | { |
1150 | struct mptsas_portinfo *port_info, *p; | 1373 | struct mptsas_portinfo *port_info, *p, *ex; |
1151 | int error = -ENOMEM, i, j; | 1374 | int error = -ENOMEM, i, j; |
1152 | 1375 | ||
1153 | port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); | 1376 | ex = kzalloc(sizeof(*port_info), GFP_KERNEL); |
1154 | if (!port_info) | 1377 | if (!ex) |
1155 | goto out; | 1378 | goto out; |
1156 | 1379 | ||
1157 | error = mptsas_sas_expander_pg0(ioc, port_info, | 1380 | error = mptsas_sas_expander_pg0(ioc, ex, |
1158 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << | 1381 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << |
1159 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); | 1382 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); |
1160 | if (error) | 1383 | if (error) |
1161 | goto out_free_port_info; | 1384 | goto out_free_port_info; |
1162 | 1385 | ||
1163 | *handle = port_info->handle; | 1386 | *handle = ex->handle; |
1164 | 1387 | ||
1165 | mutex_lock(&ioc->sas_topology_mutex); | 1388 | mutex_lock(&ioc->sas_topology_mutex); |
1166 | list_add_tail(&port_info->list, &ioc->sas_topology); | 1389 | port_info = mptsas_find_portinfo_by_handle(ioc, *handle); |
1390 | if (!port_info) { | ||
1391 | port_info = ex; | ||
1392 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
1393 | } else { | ||
1394 | port_info->handle = ex->handle; | ||
1395 | if (ex->phy_info) | ||
1396 | kfree(ex->phy_info); | ||
1397 | kfree(ex); | ||
1398 | ex = NULL; | ||
1399 | } | ||
1167 | mutex_unlock(&ioc->sas_topology_mutex); | 1400 | mutex_unlock(&ioc->sas_topology_mutex); |
1168 | 1401 | ||
1169 | for (i = 0; i < port_info->num_phys; i++) { | 1402 | for (i = 0; i < port_info->num_phys; i++) { |
@@ -1189,6 +1422,8 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | |||
1189 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 1422 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
1190 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 1423 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
1191 | port_info->phy_info[i].attached.handle); | 1424 | port_info->phy_info[i].attached.handle); |
1425 | port_info->phy_info[i].attached.phy_id = | ||
1426 | port_info->phy_info[i].phy_id; | ||
1192 | } | 1427 | } |
1193 | 1428 | ||
1194 | /* | 1429 | /* |
@@ -1208,27 +1443,137 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | |||
1208 | mutex_unlock(&ioc->sas_topology_mutex); | 1443 | mutex_unlock(&ioc->sas_topology_mutex); |
1209 | 1444 | ||
1210 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], | 1445 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], |
1211 | *index, 0); | 1446 | ioc->sas_index, 0); |
1212 | (*index)++; | 1447 | ioc->sas_index++; |
1213 | } | 1448 | } |
1214 | 1449 | ||
1215 | return 0; | 1450 | return 0; |
1216 | 1451 | ||
1217 | out_free_port_info: | 1452 | out_free_port_info: |
1218 | kfree(port_info); | 1453 | if (ex) { |
1454 | if (ex->phy_info) | ||
1455 | kfree(ex->phy_info); | ||
1456 | kfree(ex); | ||
1457 | } | ||
1219 | out: | 1458 | out: |
1220 | return error; | 1459 | return error; |
1221 | } | 1460 | } |
1222 | 1461 | ||
1462 | /* | ||
1463 | * mptsas_delete_expander_phys | ||
1464 | * | ||
1465 | * | ||
1466 | * This will traverse topology, and remove expanders | ||
1467 | * that are no longer present | ||
1468 | */ | ||
1469 | static void | ||
1470 | mptsas_delete_expander_phys(MPT_ADAPTER *ioc) | ||
1471 | { | ||
1472 | struct mptsas_portinfo buffer; | ||
1473 | struct mptsas_portinfo *port_info, *n, *parent; | ||
1474 | int i; | ||
1475 | |||
1476 | mutex_lock(&ioc->sas_topology_mutex); | ||
1477 | list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { | ||
1478 | |||
1479 | if (port_info->phy_info && | ||
1480 | (!(port_info->phy_info[0].identify.device_info & | ||
1481 | MPI_SAS_DEVICE_INFO_SMP_TARGET))) | ||
1482 | continue; | ||
1483 | |||
1484 | if (mptsas_sas_expander_pg0(ioc, &buffer, | ||
1485 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << | ||
1486 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) { | ||
1487 | |||
1488 | /* | ||
1489 | * Obtain the port_info instance to the parent port | ||
1490 | */ | ||
1491 | parent = mptsas_find_portinfo_by_handle(ioc, | ||
1492 | port_info->phy_info[0].identify.handle_parent); | ||
1493 | |||
1494 | if (!parent) | ||
1495 | goto next_port; | ||
1496 | |||
1497 | /* | ||
1498 | * Delete rphys in the parent that point | ||
1499 | * to this expander. The transport layer will | ||
1500 | * cleanup all the children. | ||
1501 | */ | ||
1502 | for (i = 0; i < parent->num_phys; i++) { | ||
1503 | if ((!parent->phy_info[i].rphy) || | ||
1504 | (parent->phy_info[i].attached.sas_address != | ||
1505 | port_info->phy_info[i].identify.sas_address)) | ||
1506 | continue; | ||
1507 | sas_rphy_delete(parent->phy_info[i].rphy); | ||
1508 | memset(&parent->phy_info[i].attached, 0, | ||
1509 | sizeof(struct mptsas_devinfo)); | ||
1510 | parent->phy_info[i].rphy = NULL; | ||
1511 | parent->phy_info[i].starget = NULL; | ||
1512 | } | ||
1513 | next_port: | ||
1514 | list_del(&port_info->list); | ||
1515 | if (port_info->phy_info) | ||
1516 | kfree(port_info->phy_info); | ||
1517 | kfree(port_info); | ||
1518 | } | ||
1519 | /* | ||
1520 | * Free this memory allocated from inside | ||
1521 | * mptsas_sas_expander_pg0 | ||
1522 | */ | ||
1523 | if (buffer.phy_info) | ||
1524 | kfree(buffer.phy_info); | ||
1525 | } | ||
1526 | mutex_unlock(&ioc->sas_topology_mutex); | ||
1527 | } | ||
1528 | |||
1529 | /* | ||
1530 | * Start of day discovery | ||
1531 | */ | ||
1223 | static void | 1532 | static void |
1224 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) | 1533 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) |
1225 | { | 1534 | { |
1226 | u32 handle = 0xFFFF; | 1535 | u32 handle = 0xFFFF; |
1227 | int index = 0; | 1536 | int i; |
1537 | |||
1538 | mutex_lock(&ioc->sas_discovery_mutex); | ||
1539 | mptsas_probe_hba_phys(ioc); | ||
1540 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
1541 | ; | ||
1542 | /* | ||
1543 | Reporting RAID volumes. | ||
1544 | */ | ||
1545 | if (!ioc->raid_data.pIocPg2) | ||
1546 | goto out; | ||
1547 | if (!ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
1548 | goto out; | ||
1549 | for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { | ||
1550 | scsi_add_device(ioc->sh, ioc->num_ports, | ||
1551 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); | ||
1552 | } | ||
1553 | out: | ||
1554 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
1555 | } | ||
1556 | |||
1557 | /* | ||
1558 | * Work queue thread to handle Runtime discovery | ||
1559 | * Mere purpose is the hot add/delete of expanders | ||
1560 | */ | ||
1561 | static void | ||
1562 | mptscsih_discovery_work(void * arg) | ||
1563 | { | ||
1564 | struct mptsas_discovery_event *ev = arg; | ||
1565 | MPT_ADAPTER *ioc = ev->ioc; | ||
1566 | u32 handle = 0xFFFF; | ||
1228 | 1567 | ||
1229 | mptsas_probe_hba_phys(ioc, &index); | 1568 | mutex_lock(&ioc->sas_discovery_mutex); |
1230 | while (!mptsas_probe_expander_phys(ioc, &handle, &index)) | 1569 | ioc->sas_discovery_runtime=1; |
1570 | mptsas_delete_expander_phys(ioc); | ||
1571 | mptsas_probe_hba_phys(ioc); | ||
1572 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
1231 | ; | 1573 | ; |
1574 | kfree(ev); | ||
1575 | ioc->sas_discovery_runtime=0; | ||
1576 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
1232 | } | 1577 | } |
1233 | 1578 | ||
1234 | static struct mptsas_phyinfo * | 1579 | static struct mptsas_phyinfo * |
@@ -1246,10 +1591,8 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) | |||
1246 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 1591 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
1247 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 1592 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
1248 | parent_handle); | 1593 | parent_handle); |
1249 | if (error) { | 1594 | if (error) |
1250 | printk("mptsas: failed to retrieve device page\n"); | ||
1251 | return NULL; | 1595 | return NULL; |
1252 | } | ||
1253 | 1596 | ||
1254 | /* | 1597 | /* |
1255 | * The phy_info structures are never deallocated during lifetime of | 1598 | * The phy_info structures are never deallocated during lifetime of |
@@ -1296,6 +1639,35 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) | |||
1296 | return phy_info; | 1639 | return phy_info; |
1297 | } | 1640 | } |
1298 | 1641 | ||
1642 | /* | ||
1643 | * Work queue thread to clear the persitency table | ||
1644 | */ | ||
1645 | static void | ||
1646 | mptscsih_sas_persist_clear_table(void * arg) | ||
1647 | { | ||
1648 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; | ||
1649 | |||
1650 | mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
1651 | } | ||
1652 | |||
1653 | static void | ||
1654 | mptsas_reprobe_lun(struct scsi_device *sdev, void *data) | ||
1655 | { | ||
1656 | sdev->no_uld_attach = data ? 1 : 0; | ||
1657 | scsi_device_reprobe(sdev); | ||
1658 | } | ||
1659 | |||
1660 | static void | ||
1661 | mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) | ||
1662 | { | ||
1663 | starget_for_each_device(starget, uld_attach ? (void *)1 : NULL, | ||
1664 | mptsas_reprobe_lun); | ||
1665 | } | ||
1666 | |||
1667 | |||
1668 | /* | ||
1669 | * Work queue thread to handle SAS hotplug events | ||
1670 | */ | ||
1299 | static void | 1671 | static void |
1300 | mptsas_hotplug_work(void *arg) | 1672 | mptsas_hotplug_work(void *arg) |
1301 | { | 1673 | { |
@@ -1304,16 +1676,39 @@ mptsas_hotplug_work(void *arg) | |||
1304 | struct mptsas_phyinfo *phy_info; | 1676 | struct mptsas_phyinfo *phy_info; |
1305 | struct sas_rphy *rphy; | 1677 | struct sas_rphy *rphy; |
1306 | struct scsi_device *sdev; | 1678 | struct scsi_device *sdev; |
1679 | struct sas_identify identify; | ||
1307 | char *ds = NULL; | 1680 | char *ds = NULL; |
1308 | struct mptsas_devinfo sas_device; | 1681 | struct mptsas_devinfo sas_device; |
1682 | VirtTarget *vtarget; | ||
1683 | |||
1684 | mutex_lock(&ioc->sas_discovery_mutex); | ||
1309 | 1685 | ||
1310 | switch (ev->event_type) { | 1686 | switch (ev->event_type) { |
1311 | case MPTSAS_DEL_DEVICE: | 1687 | case MPTSAS_DEL_DEVICE: |
1312 | 1688 | ||
1313 | phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); | 1689 | phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); |
1314 | if (!phy_info) { | 1690 | |
1315 | printk("mptsas: remove event for non-existant PHY.\n"); | 1691 | /* |
1692 | * Sanity checks, for non-existing phys and remote rphys. | ||
1693 | */ | ||
1694 | if (!phy_info) | ||
1316 | break; | 1695 | break; |
1696 | if (!phy_info->rphy) | ||
1697 | break; | ||
1698 | if (phy_info->starget) { | ||
1699 | vtarget = phy_info->starget->hostdata; | ||
1700 | |||
1701 | if (!vtarget) | ||
1702 | break; | ||
1703 | /* | ||
1704 | * Handling RAID components | ||
1705 | */ | ||
1706 | if (ev->phys_disk_num_valid) { | ||
1707 | vtarget->target_id = ev->phys_disk_num; | ||
1708 | vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
1709 | mptsas_reprobe_target(vtarget->starget, 1); | ||
1710 | break; | ||
1711 | } | ||
1317 | } | 1712 | } |
1318 | 1713 | ||
1319 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | 1714 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) |
@@ -1327,55 +1722,74 @@ mptsas_hotplug_work(void *arg) | |||
1327 | "removing %s device, channel %d, id %d, phy %d\n", | 1722 | "removing %s device, channel %d, id %d, phy %d\n", |
1328 | ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); | 1723 | ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); |
1329 | 1724 | ||
1330 | if (phy_info->rphy) { | 1725 | sas_rphy_delete(phy_info->rphy); |
1331 | sas_rphy_delete(phy_info->rphy); | 1726 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); |
1332 | phy_info->rphy = NULL; | 1727 | phy_info->rphy = NULL; |
1333 | } | 1728 | phy_info->starget = NULL; |
1334 | break; | 1729 | break; |
1335 | case MPTSAS_ADD_DEVICE: | 1730 | case MPTSAS_ADD_DEVICE: |
1336 | 1731 | ||
1337 | /* | 1732 | /* |
1338 | * When there is no sas address, | 1733 | * Refresh sas device pg0 data |
1339 | * RAID volumes are being deleted, | ||
1340 | * and hidden phy disk are being added. | ||
1341 | * We don't know the SAS data yet, | ||
1342 | * so lookup sas device page to get | ||
1343 | * pertaining info | ||
1344 | */ | 1734 | */ |
1345 | if (!ev->sas_address) { | 1735 | if (mptsas_sas_device_pg0(ioc, &sas_device, |
1346 | if (mptsas_sas_device_pg0(ioc, | 1736 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
1347 | &sas_device, ev->id, | 1737 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) |
1348 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | 1738 | break; |
1349 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT))) | ||
1350 | break; | ||
1351 | ev->handle = sas_device.handle; | ||
1352 | ev->parent_handle = sas_device.handle_parent; | ||
1353 | ev->channel = sas_device.channel; | ||
1354 | ev->phy_id = sas_device.phy_id; | ||
1355 | ev->sas_address = sas_device.sas_address; | ||
1356 | ev->device_info = sas_device.device_info; | ||
1357 | } | ||
1358 | 1739 | ||
1359 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | 1740 | phy_info = mptsas_find_phyinfo_by_parent(ioc, |
1360 | ev->parent_handle, ev->phy_id); | 1741 | sas_device.handle_parent, sas_device.phy_id); |
1742 | |||
1361 | if (!phy_info) { | 1743 | if (!phy_info) { |
1362 | printk("mptsas: add event for non-existant PHY.\n"); | 1744 | u32 handle = 0xFFFF; |
1363 | break; | 1745 | |
1746 | /* | ||
1747 | * Its possible when an expander has been hot added | ||
1748 | * containing attached devices, the sas firmware | ||
1749 | * may send a RC_ADDED event prior to the | ||
1750 | * DISCOVERY STOP event. If that occurs, our | ||
1751 | * view of the topology in the driver in respect to this | ||
1752 | * expander might of not been setup, and we hit this | ||
1753 | * condition. | ||
1754 | * Therefore, this code kicks off discovery to | ||
1755 | * refresh the data. | ||
1756 | * Then again, we check whether the parent phy has | ||
1757 | * been created. | ||
1758 | */ | ||
1759 | ioc->sas_discovery_runtime=1; | ||
1760 | mptsas_delete_expander_phys(ioc); | ||
1761 | mptsas_probe_hba_phys(ioc); | ||
1762 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
1763 | ; | ||
1764 | ioc->sas_discovery_runtime=0; | ||
1765 | |||
1766 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | ||
1767 | sas_device.handle_parent, sas_device.phy_id); | ||
1768 | if (!phy_info) | ||
1769 | break; | ||
1364 | } | 1770 | } |
1365 | 1771 | ||
1366 | if (phy_info->rphy) { | 1772 | if (phy_info->starget) { |
1367 | printk("mptsas: trying to add existing device.\n"); | 1773 | vtarget = phy_info->starget->hostdata; |
1774 | |||
1775 | if (!vtarget) | ||
1776 | break; | ||
1777 | /* | ||
1778 | * Handling RAID components | ||
1779 | */ | ||
1780 | if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { | ||
1781 | vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
1782 | vtarget->target_id = ev->id; | ||
1783 | mptsas_reprobe_target(phy_info->starget, 0); | ||
1784 | } | ||
1368 | break; | 1785 | break; |
1369 | } | 1786 | } |
1370 | 1787 | ||
1371 | /* fill attached info */ | 1788 | if (phy_info->rphy) |
1372 | phy_info->attached.handle = ev->handle; | 1789 | break; |
1373 | phy_info->attached.phy_id = ev->phy_id; | 1790 | |
1374 | phy_info->attached.port_id = phy_info->identify.port_id; | 1791 | memcpy(&phy_info->attached, &sas_device, |
1375 | phy_info->attached.id = ev->id; | 1792 | sizeof(struct mptsas_devinfo)); |
1376 | phy_info->attached.channel = ev->channel; | ||
1377 | phy_info->attached.sas_address = ev->sas_address; | ||
1378 | phy_info->attached.device_info = ev->device_info; | ||
1379 | 1793 | ||
1380 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | 1794 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) |
1381 | ds = "ssp"; | 1795 | ds = "ssp"; |
@@ -1388,13 +1802,23 @@ mptsas_hotplug_work(void *arg) | |||
1388 | "attaching %s device, channel %d, id %d, phy %d\n", | 1802 | "attaching %s device, channel %d, id %d, phy %d\n", |
1389 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | 1803 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); |
1390 | 1804 | ||
1391 | 1805 | mptsas_parse_device_info(&identify, &phy_info->attached); | |
1392 | rphy = sas_rphy_alloc(phy_info->phy); | 1806 | switch (identify.device_type) { |
1807 | case SAS_END_DEVICE: | ||
1808 | rphy = sas_end_device_alloc(phy_info->phy); | ||
1809 | break; | ||
1810 | case SAS_EDGE_EXPANDER_DEVICE: | ||
1811 | case SAS_FANOUT_EXPANDER_DEVICE: | ||
1812 | rphy = sas_expander_alloc(phy_info->phy, identify.device_type); | ||
1813 | break; | ||
1814 | default: | ||
1815 | rphy = NULL; | ||
1816 | break; | ||
1817 | } | ||
1393 | if (!rphy) | 1818 | if (!rphy) |
1394 | break; /* non-fatal: an rphy can be added later */ | 1819 | break; /* non-fatal: an rphy can be added later */ |
1395 | 1820 | ||
1396 | rphy->scsi_target_id = phy_info->attached.id; | 1821 | rphy->identify = identify; |
1397 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); | ||
1398 | if (sas_rphy_add(rphy)) { | 1822 | if (sas_rphy_add(rphy)) { |
1399 | sas_rphy_free(rphy); | 1823 | sas_rphy_free(rphy); |
1400 | break; | 1824 | break; |
@@ -1413,7 +1837,7 @@ mptsas_hotplug_work(void *arg) | |||
1413 | break; | 1837 | break; |
1414 | } | 1838 | } |
1415 | printk(MYIOC_s_INFO_FMT | 1839 | printk(MYIOC_s_INFO_FMT |
1416 | "attaching device, channel %d, id %d\n", | 1840 | "attaching raid volume, channel %d, id %d\n", |
1417 | ioc->name, ioc->num_ports, ev->id); | 1841 | ioc->name, ioc->num_ports, ev->id); |
1418 | scsi_add_device(ioc->sh, | 1842 | scsi_add_device(ioc->sh, |
1419 | ioc->num_ports, | 1843 | ioc->num_ports, |
@@ -1430,7 +1854,7 @@ mptsas_hotplug_work(void *arg) | |||
1430 | if (!sdev) | 1854 | if (!sdev) |
1431 | break; | 1855 | break; |
1432 | printk(MYIOC_s_INFO_FMT | 1856 | printk(MYIOC_s_INFO_FMT |
1433 | "removing device, channel %d, id %d\n", | 1857 | "removing raid volume, channel %d, id %d\n", |
1434 | ioc->name, ioc->num_ports, ev->id); | 1858 | ioc->name, ioc->num_ports, ev->id); |
1435 | scsi_remove_device(sdev); | 1859 | scsi_remove_device(sdev); |
1436 | scsi_device_put(sdev); | 1860 | scsi_device_put(sdev); |
@@ -1439,6 +1863,7 @@ mptsas_hotplug_work(void *arg) | |||
1439 | } | 1863 | } |
1440 | 1864 | ||
1441 | kfree(ev); | 1865 | kfree(ev); |
1866 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
1442 | } | 1867 | } |
1443 | 1868 | ||
1444 | static void | 1869 | static void |
@@ -1455,35 +1880,51 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, | |||
1455 | MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) | 1880 | MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) |
1456 | return; | 1881 | return; |
1457 | 1882 | ||
1458 | if ((sas_event_data->ReasonCode & | 1883 | switch (sas_event_data->ReasonCode) { |
1459 | (MPI_EVENT_SAS_DEV_STAT_RC_ADDED | | 1884 | case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: |
1460 | MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING)) == 0) | 1885 | case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: |
1461 | return; | 1886 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); |
1887 | if (!ev) { | ||
1888 | printk(KERN_WARNING "mptsas: lost hotplug event\n"); | ||
1889 | break; | ||
1890 | } | ||
1462 | 1891 | ||
1463 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); | 1892 | INIT_WORK(&ev->work, mptsas_hotplug_work, ev); |
1464 | if (!ev) { | 1893 | ev->ioc = ioc; |
1465 | printk(KERN_WARNING "mptsas: lost hotplug event\n"); | 1894 | ev->handle = le16_to_cpu(sas_event_data->DevHandle); |
1466 | return; | 1895 | ev->parent_handle = |
1896 | le16_to_cpu(sas_event_data->ParentDevHandle); | ||
1897 | ev->channel = sas_event_data->Bus; | ||
1898 | ev->id = sas_event_data->TargetID; | ||
1899 | ev->phy_id = sas_event_data->PhyNum; | ||
1900 | memcpy(&sas_address, &sas_event_data->SASAddress, | ||
1901 | sizeof(__le64)); | ||
1902 | ev->sas_address = le64_to_cpu(sas_address); | ||
1903 | ev->device_info = device_info; | ||
1904 | |||
1905 | if (sas_event_data->ReasonCode & | ||
1906 | MPI_EVENT_SAS_DEV_STAT_RC_ADDED) | ||
1907 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
1908 | else | ||
1909 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
1910 | schedule_work(&ev->work); | ||
1911 | break; | ||
1912 | case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: | ||
1913 | /* | ||
1914 | * Persistent table is full. | ||
1915 | */ | ||
1916 | INIT_WORK(&ioc->mptscsih_persistTask, | ||
1917 | mptscsih_sas_persist_clear_table, | ||
1918 | (void *)ioc); | ||
1919 | schedule_work(&ioc->mptscsih_persistTask); | ||
1920 | break; | ||
1921 | case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: | ||
1922 | /* TODO */ | ||
1923 | case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: | ||
1924 | /* TODO */ | ||
1925 | default: | ||
1926 | break; | ||
1467 | } | 1927 | } |
1468 | |||
1469 | |||
1470 | INIT_WORK(&ev->work, mptsas_hotplug_work, ev); | ||
1471 | ev->ioc = ioc; | ||
1472 | ev->handle = le16_to_cpu(sas_event_data->DevHandle); | ||
1473 | ev->parent_handle = le16_to_cpu(sas_event_data->ParentDevHandle); | ||
1474 | ev->channel = sas_event_data->Bus; | ||
1475 | ev->id = sas_event_data->TargetID; | ||
1476 | ev->phy_id = sas_event_data->PhyNum; | ||
1477 | memcpy(&sas_address, &sas_event_data->SASAddress, sizeof(__le64)); | ||
1478 | ev->sas_address = le64_to_cpu(sas_address); | ||
1479 | ev->device_info = device_info; | ||
1480 | |||
1481 | if (sas_event_data->ReasonCode & MPI_EVENT_SAS_DEV_STAT_RC_ADDED) | ||
1482 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
1483 | else | ||
1484 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
1485 | |||
1486 | schedule_work(&ev->work); | ||
1487 | } | 1928 | } |
1488 | 1929 | ||
1489 | static void | 1930 | static void |
@@ -1512,6 +1953,9 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, | |||
1512 | ev->event_type = MPTSAS_ADD_DEVICE; | 1953 | ev->event_type = MPTSAS_ADD_DEVICE; |
1513 | break; | 1954 | break; |
1514 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: | 1955 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: |
1956 | ioc->raid_data.isRaid = 1; | ||
1957 | ev->phys_disk_num_valid = 1; | ||
1958 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | ||
1515 | ev->event_type = MPTSAS_DEL_DEVICE; | 1959 | ev->event_type = MPTSAS_DEL_DEVICE; |
1516 | break; | 1960 | break; |
1517 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: | 1961 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: |
@@ -1533,15 +1977,31 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, | |||
1533 | schedule_work(&ev->work); | 1977 | schedule_work(&ev->work); |
1534 | } | 1978 | } |
1535 | 1979 | ||
1536 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1537 | /* work queue thread to clear the persitency table */ | ||
1538 | static void | 1980 | static void |
1539 | mptscsih_sas_persist_clear_table(void * arg) | 1981 | mptscsih_send_discovery(MPT_ADAPTER *ioc, |
1982 | EVENT_DATA_SAS_DISCOVERY *discovery_data) | ||
1540 | { | 1983 | { |
1541 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; | 1984 | struct mptsas_discovery_event *ev; |
1985 | |||
1986 | /* | ||
1987 | * DiscoveryStatus | ||
1988 | * | ||
1989 | * This flag will be non-zero when firmware | ||
1990 | * kicks off discovery, and return to zero | ||
1991 | * once its completed. | ||
1992 | */ | ||
1993 | if (discovery_data->DiscoveryStatus) | ||
1994 | return; | ||
1995 | |||
1996 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); | ||
1997 | if (!ev) | ||
1998 | return; | ||
1999 | memset(ev,0,sizeof(struct mptsas_discovery_event)); | ||
2000 | INIT_WORK(&ev->work, mptscsih_discovery_work, ev); | ||
2001 | ev->ioc = ioc; | ||
2002 | schedule_work(&ev->work); | ||
2003 | }; | ||
1542 | 2004 | ||
1543 | mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
1544 | } | ||
1545 | 2005 | ||
1546 | static int | 2006 | static int |
1547 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | 2007 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) |
@@ -1552,6 +2012,17 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | |||
1552 | if (!ioc->sh) | 2012 | if (!ioc->sh) |
1553 | goto out; | 2013 | goto out; |
1554 | 2014 | ||
2015 | /* | ||
2016 | * sas_discovery_ignore_events | ||
2017 | * | ||
2018 | * This flag is to prevent anymore processing of | ||
2019 | * sas events once mptsas_remove function is called. | ||
2020 | */ | ||
2021 | if (ioc->sas_discovery_ignore_events) { | ||
2022 | rc = mptscsih_event_process(ioc, reply); | ||
2023 | goto out; | ||
2024 | } | ||
2025 | |||
1555 | switch (event) { | 2026 | switch (event) { |
1556 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | 2027 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
1557 | mptscsih_send_sas_event(ioc, | 2028 | mptscsih_send_sas_event(ioc, |
@@ -1567,6 +2038,10 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | |||
1567 | (void *)ioc); | 2038 | (void *)ioc); |
1568 | schedule_work(&ioc->mptscsih_persistTask); | 2039 | schedule_work(&ioc->mptscsih_persistTask); |
1569 | break; | 2040 | break; |
2041 | case MPI_EVENT_SAS_DISCOVERY: | ||
2042 | mptscsih_send_discovery(ioc, | ||
2043 | (EVENT_DATA_SAS_DISCOVERY *)reply->Data); | ||
2044 | break; | ||
1570 | default: | 2045 | default: |
1571 | rc = mptscsih_event_process(ioc, reply); | 2046 | rc = mptscsih_event_process(ioc, reply); |
1572 | break; | 2047 | break; |
@@ -1668,7 +2143,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1668 | 2143 | ||
1669 | INIT_LIST_HEAD(&ioc->sas_topology); | 2144 | INIT_LIST_HEAD(&ioc->sas_topology); |
1670 | mutex_init(&ioc->sas_topology_mutex); | 2145 | mutex_init(&ioc->sas_topology_mutex); |
1671 | 2146 | mutex_init(&ioc->sas_discovery_mutex); | |
1672 | mutex_init(&ioc->sas_mgmt.mutex); | 2147 | mutex_init(&ioc->sas_mgmt.mutex); |
1673 | init_completion(&ioc->sas_mgmt.done); | 2148 | init_completion(&ioc->sas_mgmt.done); |
1674 | 2149 | ||
@@ -1781,20 +2256,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1781 | 2256 | ||
1782 | mptsas_scan_sas_topology(ioc); | 2257 | mptsas_scan_sas_topology(ioc); |
1783 | 2258 | ||
1784 | /* | ||
1785 | Reporting RAID volumes. | ||
1786 | */ | ||
1787 | if (!ioc->raid_data.pIocPg2) | ||
1788 | return 0; | ||
1789 | if (!ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
1790 | return 0; | ||
1791 | for (ii=0;ii<ioc->raid_data.pIocPg2->NumActiveVolumes;ii++) { | ||
1792 | scsi_add_device(sh, | ||
1793 | ioc->num_ports, | ||
1794 | ioc->raid_data.pIocPg2->RaidVolume[ii].VolumeID, | ||
1795 | 0); | ||
1796 | } | ||
1797 | |||
1798 | return 0; | 2259 | return 0; |
1799 | 2260 | ||
1800 | out_mptsas_probe: | 2261 | out_mptsas_probe: |
@@ -1808,11 +2269,14 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) | |||
1808 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 2269 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
1809 | struct mptsas_portinfo *p, *n; | 2270 | struct mptsas_portinfo *p, *n; |
1810 | 2271 | ||
2272 | ioc->sas_discovery_ignore_events=1; | ||
1811 | sas_remove_host(ioc->sh); | 2273 | sas_remove_host(ioc->sh); |
1812 | 2274 | ||
1813 | mutex_lock(&ioc->sas_topology_mutex); | 2275 | mutex_lock(&ioc->sas_topology_mutex); |
1814 | list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { | 2276 | list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { |
1815 | list_del(&p->list); | 2277 | list_del(&p->list); |
2278 | if (p->phy_info) | ||
2279 | kfree(p->phy_info); | ||
1816 | kfree(p); | 2280 | kfree(p); |
1817 | } | 2281 | } |
1818 | mutex_unlock(&ioc->sas_topology_mutex); | 2282 | mutex_unlock(&ioc->sas_topology_mutex); |
@@ -1867,7 +2331,7 @@ mptsas_init(void) | |||
1867 | mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); | 2331 | mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); |
1868 | 2332 | ||
1869 | if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) { | 2333 | if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) { |
1870 | devtprintk((KERN_INFO MYNAM | 2334 | devtverboseprintk((KERN_INFO MYNAM |
1871 | ": Registered for IOC event notifications\n")); | 2335 | ": Registered for IOC event notifications\n")); |
1872 | } | 2336 | } |
1873 | 2337 | ||