diff options
-rw-r--r-- | drivers/message/fusion/mptsas.c | 196 |
1 files changed, 161 insertions, 35 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 2512d0e6155e..74f4368c79ab 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -117,6 +117,8 @@ struct mptsas_hotplug_event { | |||
117 | struct mptsas_devinfo { | 117 | struct mptsas_devinfo { |
118 | u16 handle; /* unique id to address this device */ | 118 | u16 handle; /* unique id to address this device */ |
119 | u16 handle_parent; /* unique id to address parent device */ | 119 | u16 handle_parent; /* unique id to address parent device */ |
120 | u16 handle_enclosure; /* enclosure identifier of the enclosure */ | ||
121 | u16 slot; /* physical slot in enclosure */ | ||
120 | u8 phy_id; /* phy number of parent device */ | 122 | u8 phy_id; /* phy number of parent device */ |
121 | u8 port_id; /* sas physical port this device | 123 | u8 port_id; /* sas physical port this device |
122 | is assoc'd with */ | 124 | is assoc'd with */ |
@@ -146,6 +148,18 @@ struct mptsas_portinfo { | |||
146 | struct mptsas_phyinfo *phy_info; | 148 | struct mptsas_phyinfo *phy_info; |
147 | }; | 149 | }; |
148 | 150 | ||
151 | struct mptsas_enclosure { | ||
152 | u64 enclosure_logical_id; /* The WWN for the enclosure */ | ||
153 | u16 enclosure_handle; /* unique id to address this */ | ||
154 | u16 flags; /* details enclosure management */ | ||
155 | u16 num_slot; /* num slots */ | ||
156 | u16 start_slot; /* first slot */ | ||
157 | u8 start_id; /* starting logical target id */ | ||
158 | u8 start_channel; /* starting logical channel id */ | ||
159 | u8 sep_id; /* SEP device logical target id */ | ||
160 | u8 sep_channel; /* SEP channel logical channel id */ | ||
161 | }; | ||
162 | |||
149 | 163 | ||
150 | #ifdef SASDEBUG | 164 | #ifdef SASDEBUG |
151 | static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) | 165 | static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) |
@@ -205,6 +219,7 @@ static void mptsas_print_device_pg0(SasDevicePage0_t *pg0) | |||
205 | 219 | ||
206 | printk("---- SAS DEVICE PAGE 0 ---------\n"); | 220 | printk("---- SAS DEVICE PAGE 0 ---------\n"); |
207 | printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)); | 221 | printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)); |
222 | printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)); | ||
208 | printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)); | 223 | printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)); |
209 | printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot)); | 224 | printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot)); |
210 | printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); | 225 | printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); |
@@ -243,6 +258,82 @@ static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1) | |||
243 | #define mptsas_print_expander_pg1(pg1) do { } while (0) | 258 | #define mptsas_print_expander_pg1(pg1) do { } while (0) |
244 | #endif | 259 | #endif |
245 | 260 | ||
261 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) | ||
262 | { | ||
263 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | ||
264 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
265 | } | ||
266 | |||
267 | static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) | ||
268 | { | ||
269 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); | ||
270 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
271 | } | ||
272 | |||
273 | static int | ||
274 | mptsas_sas_exclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, | ||
275 | u32 form, u32 form_specific) | ||
276 | { | ||
277 | ConfigExtendedPageHeader_t hdr; | ||
278 | CONFIGPARMS cfg; | ||
279 | SasEnclosurePage0_t *buffer; | ||
280 | dma_addr_t dma_handle; | ||
281 | int error; | ||
282 | __le64 le_identifier; | ||
283 | |||
284 | memset(&hdr, 0, sizeof(hdr)); | ||
285 | hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; | ||
286 | hdr.PageNumber = 0; | ||
287 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; | ||
288 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; | ||
289 | |||
290 | cfg.cfghdr.ehdr = &hdr; | ||
291 | cfg.physAddr = -1; | ||
292 | cfg.pageAddr = form + form_specific; | ||
293 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | ||
294 | cfg.dir = 0; /* read */ | ||
295 | cfg.timeout = 10; | ||
296 | |||
297 | error = mpt_config(ioc, &cfg); | ||
298 | if (error) | ||
299 | goto out; | ||
300 | if (!hdr.ExtPageLength) { | ||
301 | error = -ENXIO; | ||
302 | goto out; | ||
303 | } | ||
304 | |||
305 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | ||
306 | &dma_handle); | ||
307 | if (!buffer) { | ||
308 | error = -ENOMEM; | ||
309 | goto out; | ||
310 | } | ||
311 | |||
312 | cfg.physAddr = dma_handle; | ||
313 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | ||
314 | |||
315 | error = mpt_config(ioc, &cfg); | ||
316 | if (error) | ||
317 | goto out_free_consistent; | ||
318 | |||
319 | /* save config data */ | ||
320 | memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64)); | ||
321 | enclosure->enclosure_logical_id = le64_to_cpu(le_identifier); | ||
322 | enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle); | ||
323 | enclosure->flags = le16_to_cpu(buffer->Flags); | ||
324 | enclosure->num_slot = le16_to_cpu(buffer->NumSlots); | ||
325 | enclosure->start_slot = le16_to_cpu(buffer->StartSlot); | ||
326 | enclosure->start_id = buffer->StartTargetID; | ||
327 | enclosure->start_channel = buffer->StartBus; | ||
328 | enclosure->sep_id = buffer->SEPTargetID; | ||
329 | enclosure->sep_channel = buffer->SEPBus; | ||
330 | |||
331 | out_free_consistent: | ||
332 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | ||
333 | buffer, dma_handle); | ||
334 | out: | ||
335 | return error; | ||
336 | } | ||
246 | 337 | ||
247 | /* | 338 | /* |
248 | * This is pretty ugly. We will be able to seriously clean it up | 339 | * This is pretty ugly. We will be able to seriously clean it up |
@@ -399,12 +490,6 @@ static struct scsi_host_template mptsas_driver_template = { | |||
399 | .use_clustering = ENABLE_CLUSTERING, | 490 | .use_clustering = ENABLE_CLUSTERING, |
400 | }; | 491 | }; |
401 | 492 | ||
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) | 493 | static int mptsas_get_linkerrors(struct sas_phy *phy) |
409 | { | 494 | { |
410 | MPT_ADAPTER *ioc = phy_to_ioc(phy); | 495 | MPT_ADAPTER *ioc = phy_to_ioc(phy); |
@@ -546,8 +631,67 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
546 | return error; | 631 | return error; |
547 | } | 632 | } |
548 | 633 | ||
634 | static int | ||
635 | mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) | ||
636 | { | ||
637 | MPT_ADAPTER *ioc = rphy_to_ioc(rphy); | ||
638 | int i, error; | ||
639 | struct mptsas_portinfo *p; | ||
640 | struct mptsas_enclosure enclosure_info; | ||
641 | u64 enclosure_handle; | ||
642 | |||
643 | mutex_lock(&ioc->sas_topology_mutex); | ||
644 | list_for_each_entry(p, &ioc->sas_topology, list) { | ||
645 | for (i = 0; i < p->num_phys; i++) { | ||
646 | if (p->phy_info[i].attached.sas_address == | ||
647 | rphy->identify.sas_address) { | ||
648 | enclosure_handle = p->phy_info[i]. | ||
649 | attached.handle_enclosure; | ||
650 | goto found_info; | ||
651 | } | ||
652 | } | ||
653 | } | ||
654 | mutex_unlock(&ioc->sas_topology_mutex); | ||
655 | return -ENXIO; | ||
656 | |||
657 | found_info: | ||
658 | mutex_unlock(&ioc->sas_topology_mutex); | ||
659 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); | ||
660 | error = mptsas_sas_exclosure_pg0(ioc, &enclosure_info, | ||
661 | (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << | ||
662 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle); | ||
663 | if (!error) | ||
664 | *identifier = enclosure_info.enclosure_logical_id; | ||
665 | return error; | ||
666 | } | ||
667 | |||
668 | static int | ||
669 | mptsas_get_bay_identifier(struct sas_rphy *rphy) | ||
670 | { | ||
671 | MPT_ADAPTER *ioc = rphy_to_ioc(rphy); | ||
672 | struct mptsas_portinfo *p; | ||
673 | int i, rc; | ||
674 | |||
675 | mutex_lock(&ioc->sas_topology_mutex); | ||
676 | list_for_each_entry(p, &ioc->sas_topology, list) { | ||
677 | for (i = 0; i < p->num_phys; i++) { | ||
678 | if (p->phy_info[i].attached.sas_address == | ||
679 | rphy->identify.sas_address) { | ||
680 | rc = p->phy_info[i].attached.slot; | ||
681 | goto out; | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | rc = -ENXIO; | ||
686 | out: | ||
687 | mutex_unlock(&ioc->sas_topology_mutex); | ||
688 | return rc; | ||
689 | } | ||
690 | |||
549 | static struct sas_function_template mptsas_transport_functions = { | 691 | static struct sas_function_template mptsas_transport_functions = { |
550 | .get_linkerrors = mptsas_get_linkerrors, | 692 | .get_linkerrors = mptsas_get_linkerrors, |
693 | .get_enclosure_identifier = mptsas_get_enclosure_identifier, | ||
694 | .get_bay_identifier = mptsas_get_bay_identifier, | ||
551 | .phy_reset = mptsas_phy_reset, | 695 | .phy_reset = mptsas_phy_reset, |
552 | }; | 696 | }; |
553 | 697 | ||
@@ -739,6 +883,9 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
739 | 883 | ||
740 | device_info->handle = le16_to_cpu(buffer->DevHandle); | 884 | device_info->handle = le16_to_cpu(buffer->DevHandle); |
741 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); | 885 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); |
886 | device_info->handle_enclosure = | ||
887 | le16_to_cpu(buffer->EnclosureHandle); | ||
888 | device_info->slot = le16_to_cpu(buffer->Slot); | ||
742 | device_info->phy_id = buffer->PhyNum; | 889 | device_info->phy_id = buffer->PhyNum; |
743 | device_info->port_id = buffer->PhysicalPort; | 890 | device_info->port_id = buffer->PhysicalPort; |
744 | device_info->id = buffer->TargetID; | 891 | device_info->id = buffer->TargetID; |
@@ -1335,29 +1482,15 @@ mptsas_hotplug_work(void *arg) | |||
1335 | case MPTSAS_ADD_DEVICE: | 1482 | case MPTSAS_ADD_DEVICE: |
1336 | 1483 | ||
1337 | /* | 1484 | /* |
1338 | * When there is no sas address, | 1485 | * 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 | */ | 1486 | */ |
1345 | if (!ev->sas_address) { | 1487 | if (mptsas_sas_device_pg0(ioc, &sas_device, |
1346 | if (mptsas_sas_device_pg0(ioc, | 1488 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
1347 | &sas_device, ev->id, | 1489 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) |
1348 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | 1490 | 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 | 1491 | ||
1359 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | 1492 | phy_info = mptsas_find_phyinfo_by_parent(ioc, |
1360 | ev->parent_handle, ev->phy_id); | 1493 | sas_device.handle_parent, sas_device.phy_id); |
1361 | if (!phy_info) { | 1494 | if (!phy_info) { |
1362 | printk("mptsas: add event for non-existant PHY.\n"); | 1495 | printk("mptsas: add event for non-existant PHY.\n"); |
1363 | break; | 1496 | break; |
@@ -1368,14 +1501,8 @@ mptsas_hotplug_work(void *arg) | |||
1368 | break; | 1501 | break; |
1369 | } | 1502 | } |
1370 | 1503 | ||
1371 | /* fill attached info */ | 1504 | memcpy(&phy_info->attached, &sas_device, |
1372 | phy_info->attached.handle = ev->handle; | 1505 | sizeof(struct mptsas_devinfo)); |
1373 | phy_info->attached.phy_id = ev->phy_id; | ||
1374 | phy_info->attached.port_id = phy_info->identify.port_id; | ||
1375 | phy_info->attached.id = ev->id; | ||
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 | 1506 | ||
1380 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | 1507 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) |
1381 | ds = "ssp"; | 1508 | ds = "ssp"; |
@@ -1393,7 +1520,6 @@ mptsas_hotplug_work(void *arg) | |||
1393 | if (!rphy) | 1520 | if (!rphy) |
1394 | break; /* non-fatal: an rphy can be added later */ | 1521 | break; /* non-fatal: an rphy can be added later */ |
1395 | 1522 | ||
1396 | rphy->scsi_target_id = phy_info->attached.id; | ||
1397 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); | 1523 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); |
1398 | if (sas_rphy_add(rphy)) { | 1524 | if (sas_rphy_add(rphy)) { |
1399 | sas_rphy_free(rphy); | 1525 | sas_rphy_free(rphy); |