1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
14 */
15
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <stropts.h>
22 #include <string.h>
23
24 #include <fm/topo_mod.h>
25 #include <fm/topo_list.h>
26
27 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
28 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
29 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
30 #include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
31
32 static int
33 get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure,
34 uint32_t slot, char **sas_address)
35 {
36 int err = -1;
37 int fd, i;
38 mptsas_get_disk_info_t gdi;
39 mptsas_disk_info_t *di = NULL;
40 size_t disz;
41
42 bzero(&gdi, sizeof (gdi));
43
44 fd = open(devctl, O_RDWR);
45 if (fd == -1) {
46 topo_mod_dprintf(mod, "could not open '%s' for ioctl: %s\n",
47 devctl, strerror(errno));
48 return (-1);
49 }
50
51 if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
52 topo_mod_dprintf(mod, "ioctl 1 on '%s' failed: %s\n", devctl,
53 strerror(errno));
54 goto out;
55 }
56
57 gdi.DiskInfoArraySize = disz = sizeof (mptsas_disk_info_t) *
58 gdi.DiskCount;
59 gdi.PtrDiskInfoArray = di = topo_mod_alloc(mod, disz);
60 if (di == NULL) {
61 topo_mod_dprintf(mod, "memory allocation failed\n");
62 goto out;
63 }
64
65 if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
66 topo_mod_dprintf(mod, "ioctl 2 on '%s' failed: %s\n", devctl,
67 strerror(errno));
68 goto out;
69 }
70
71 for (i = 0; i < gdi.DiskCount; i++) {
72 if (di[i].Enclosure == enclosure && di[i].Slot == slot) {
73 char sas[17]; /* 16 hex digits and NUL */
74 (void) snprintf(sas, 17, "%llx", di[i].SasAddress);
75 topo_mod_dprintf(mod, "found mpt_sas disk (%d/%d) "
76 "with adddress %s\n", enclosure, slot, sas);
77 *sas_address = topo_mod_strdup(mod, sas);
78 err = 0;
79 break;
80 }
81 }
82
83 out:
84 if (di != NULL)
85 topo_mod_free(mod, di, disz);
86 (void) close(fd);
87 return (err);
88 }
89
90 int
91 disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address)
92 {
93 char *devctl = NULL;
94 uint32_t enclosure, slot;
95 int err;
96
97 /*
98 * Get the required properties from the node. These come from
99 * the static XML mapping.
100 */
101 if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING,
102 TOPO_BINDING_DEVCTL, &devctl, &err) != 0 ||
103 topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
104 TOPO_BINDING_ENCLOSURE, &enclosure, &err) != 0 ||
105 topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
106 TOPO_BINDING_SLOT, &slot, &err) != 0) {
107 if (devctl != NULL)
108 topo_mod_strfree(mod, devctl);
109 topo_mod_dprintf(mod, "bay node was missing mpt_sas binding "
110 "properties\n");
111 return (-1);
112 }
113
114 err = get_sas_address(mod, devctl, enclosure, slot, sas_address);
115 topo_mod_strfree(mod, devctl);
116 return (err);
117 }