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  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
13  * Copyright 2023 Racktop Systems, Inc.
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 #include <strings.h>
24 
25 #include <fm/topo_mod.h>
26 #include <fm/topo_list.h>
27 
28 #include <sys/scsi/adapters/mpi/mpi2_type.h>
29 #include <sys/scsi/adapters/mpi/mpi2.h>
30 #include <sys/scsi/adapters/mpi/mpi2_init.h>
31 #include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
32 
33 #include "disk.h"
34 #include "disk_drivers.h"
35 
36 static int
get_sas_address(topo_mod_t * mod,char * devctl,uint32_t enclosure,uint32_t slot,char ** sas_address)37 get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure,
38     uint32_t slot, char **sas_address)
39 {
40 	int fd, err, i;
41 	mptsas_get_disk_info_t gdi;
42 	mptsas_disk_info_t *di;
43 	size_t disz;
44 
45 	bzero(&gdi, sizeof (gdi));
46 
47 	if ((fd = open(devctl, O_RDWR)) == -1) {
48 		topo_mod_dprintf(mod, "could not open '%s' for ioctl: %s\n",
49 		    devctl, strerror(errno));
50 		return (-1);
51 	}
52 
53 	if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
54 		topo_mod_dprintf(mod, "ioctl 1 on '%s' failed: %s\n", devctl,
55 		    strerror(errno));
56 		(void) close(fd);
57 		return (-1);
58 	}
59 
60 	gdi.DiskInfoArraySize = disz = sizeof (mptsas_disk_info_t) *
61 	    gdi.DiskCount;
62 	gdi.PtrDiskInfoArray = di = topo_mod_alloc(mod, disz);
63 	if (di == NULL) {
64 		topo_mod_dprintf(mod, "memory allocation failed\n");
65 		(void) close(fd);
66 		return (-1);
67 	}
68 
69 	if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
70 		topo_mod_dprintf(mod, "ioctl 2 on '%s' failed: %s\n", devctl,
71 		    strerror(errno));
72 		topo_mod_free(mod, di, disz);
73 		(void) close(fd);
74 		return (-1);
75 	}
76 
77 	err = -1;
78 	for (i = 0; i < gdi.DiskCount; i++) {
79 		if (di[i].Enclosure == enclosure && di[i].Slot == slot) {
80 			char sas[17]; /* 16 hex digits and NUL */
81 			(void) snprintf(sas, 17, "%llx", di[i].SasAddress);
82 			topo_mod_dprintf(mod, "found mpt_sas disk (%d/%d) "
83 			    "with adddress %s\n", enclosure, slot, sas);
84 			*sas_address = topo_mod_strdup(mod, sas);
85 			err = 0;
86 			break;
87 		}
88 	}
89 
90 	topo_mod_free(mod, di, disz);
91 	(void) close(fd);
92 	return (err);
93 }
94 
95 int
disk_mptsas_find_disk(topo_mod_t * mod,tnode_t * baynode,char ** sas_address)96 disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address)
97 {
98 	char *devctl = NULL;
99 	uint32_t enclosure, slot;
100 	int err;
101 
102 	/*
103 	 * Get the required properties from the node.  These come from
104 	 * the static XML mapping.
105 	 */
106 	if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING,
107 	    TOPO_BINDING_DEVCTL, &devctl, &err) != 0 ||
108 	    topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
109 	    TOPO_BINDING_ENCLOSURE, &enclosure, &err) != 0 ||
110 	    topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
111 	    TOPO_BINDING_SLOT, &slot, &err) != 0) {
112 		if (devctl != NULL)
113 			topo_mod_strfree(mod, devctl);
114 		topo_mod_dprintf(mod, "bay node was missing mpt_sas binding "
115 		    "properties\n");
116 		return (-1);
117 	}
118 
119 	return (get_sas_address(mod, devctl, enclosure, slot, sas_address));
120 
121 }
122