125 /*
126 * The fctl_mod_ports_lock protects the mod_ports element in the
127 * fc_ulp_ports_t structure
128 */
129
130 static krwlock_t fctl_mod_ports_lock;
131
132 /*
133 * fctl_port_lock protects the linked list of local port structures
134 * (fctl_fca_portlist). When walking the list, this lock must be obtained
135 * prior to any local port locks.
136 */
137
138 static kmutex_t fctl_port_lock;
139 static kmutex_t fctl_ulp_list_mutex;
140
141 static fctl_nwwn_list_t *fctl_nwwn_hash_table;
142 static kmutex_t fctl_nwwn_hash_mutex;
143 int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE;
144
145 #if !defined(lint)
146 _NOTE(MUTEX_PROTECTS_DATA(fctl_nwwn_hash_mutex, fctl_nwwn_hash_table))
147 _NOTE(MUTEX_PROTECTS_DATA(fctl_ulp_list_mutex, fctl_ulp_list))
148 _NOTE(RWLOCK_PROTECTS_DATA(fctl_ulp_lock, ulp_module::mod_next))
149 _NOTE(RWLOCK_PROTECTS_DATA(fctl_mod_ports_lock, ulp_module::mod_ports
150 ulp_ports::port_handle))
151 _NOTE(DATA_READABLE_WITHOUT_LOCK(ulp_module::mod_info))
152 _NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec
153 ulp_ports::port_dstate))
154 #endif /* lint */
155
156 #define FCTL_VERSION "20090729-1.70"
157 #define FCTL_NAME_VERSION "SunFC Transport v" FCTL_VERSION
158
159 char *fctl_version = FCTL_NAME_VERSION;
160
161 extern struct mod_ops mod_miscops;
162
163 static struct modlmisc modlmisc = {
164 &mod_miscops, /* type of module */
165 FCTL_NAME_VERSION /* Module name */
166 };
167
168 static struct modlinkage modlinkage = {
169 MODREV_1, (void *)&modlmisc, NULL
170 };
171
172 static struct bus_ops fctl_fca_busops = {
173 BUSO_REV,
174 nullbusmap, /* bus_map */
175 NULL, /* bus_get_intrspec */
1899
1900 if (pd) {
1901 mutex_enter(&pd->pd_mutex);
1902 pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN;
1903 mutex_exit(&pd->pd_mutex);
1904 }
1905 }
1906
1907
1908 /*
1909 * fc_fca_init
1910 * Overload the FCA bus_ops vector in its dev_ops with
1911 * fctl_fca_busops to handle all the INITchilds for "sf"
1912 * in one common place.
1913 *
1914 * Should be called from FCA _init routine.
1915 */
1916 void
1917 fc_fca_init(struct dev_ops *fca_devops_p)
1918 {
1919 #ifndef __lock_lint
1920 fca_devops_p->devo_bus_ops = &fctl_fca_busops;
1921 #endif /* __lock_lint */
1922 }
1923
1924
1925 /*
1926 * fc_fca_attach
1927 */
1928 int
1929 fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran)
1930 {
1931 /*
1932 * When we are in a position to offer downward compatibility
1933 * we should change the following check to allow lower revision
1934 * of FCAs; But we aren't there right now.
1935 */
1936 if (tran->fca_version != FCTL_FCA_MODREV_5) {
1937 const char *name = ddi_driver_name(fca_dip);
1938
1939 ASSERT(name != NULL);
1940
1941 cmn_err(CE_WARN, "fctl: FCA %s version mismatch"
2426 }
2427
2428
2429 void
2430 fctl_remove_port(fc_local_port_t *port)
2431 {
2432 fc_ulp_module_t *mod;
2433 fc_fca_port_t *prev;
2434 fc_fca_port_t *list;
2435 fc_ulp_ports_t *ulp_port;
2436
2437 rw_enter(&fctl_ulp_lock, RW_WRITER);
2438 rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2439
2440 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2441 ulp_port = fctl_get_ulp_port(mod, port);
2442 if (ulp_port == NULL) {
2443 continue;
2444 }
2445
2446 #ifndef __lock_lint
2447 ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0);
2448 #endif /* __lock_lint */
2449
2450 (void) fctl_remove_ulp_port(mod, port);
2451 }
2452
2453 rw_exit(&fctl_mod_ports_lock);
2454 rw_exit(&fctl_ulp_lock);
2455
2456 mutex_enter(&fctl_port_lock);
2457
2458 list = fctl_fca_portlist;
2459 prev = NULL;
2460 while (list != NULL) {
2461 if (list->port_handle == port) {
2462 if (prev == NULL) {
2463 fctl_fca_portlist = list->port_next;
2464 } else {
2465 prev->port_next = list->port_next;
2466 }
2467 kmem_free(list, sizeof (*list));
2468 break;
3865 head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3866
3867 pd = head->d_id_head;
3868 while (pd != NULL) {
3869 mutex_enter(&pd->pd_mutex);
3870 if (pd->pd_port_id.port_id == d_id) {
3871 /* Match found -- break out of the loop */
3872 mutex_exit(&pd->pd_mutex);
3873 break;
3874 }
3875 mutex_exit(&pd->pd_mutex);
3876 pd = pd->pd_did_hnext;
3877 }
3878
3879 mutex_exit(&port->fp_mutex);
3880
3881 return (pd);
3882 }
3883
3884
3885 #ifndef __lock_lint /* uncomment when there is a consumer */
3886
3887 void
3888 fc_ulp_hold_remote_port(opaque_t port_handle)
3889 {
3890 fc_remote_port_t *pd = port_handle;
3891
3892 mutex_enter(&pd->pd_mutex);
3893 pd->pd_ref_count++;
3894 mutex_exit(&pd->pd_mutex);
3895 }
3896
3897 /*
3898 * Looks in the d_id table of the specified fc_local_port_t for the
3899 * fc_remote_port_t that matches the given d_id. Hashes based upon
3900 * the given d_id. Returns a pointer to the fc_remote_port_t struct.
3901 *
3902 * Increments pd_ref_count in the fc_remote_port_t if the
3903 * fc_remote_port_t is found at the given d_id.
3904 *
3905 * The fc_remote_port_t is ignored (treated as non-existent) if either
3906 * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
3919
3920 pd = head->d_id_head;
3921 while (pd != NULL) {
3922 mutex_enter(&pd->pd_mutex);
3923 if (pd->pd_port_id.port_id == d_id && pd->pd_state !=
3924 PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) {
3925 ASSERT(pd->pd_ref_count >= 0);
3926 pd->pd_ref_count++;
3927 mutex_exit(&pd->pd_mutex);
3928 break;
3929 }
3930 mutex_exit(&pd->pd_mutex);
3931 pd = pd->pd_did_hnext;
3932 }
3933
3934 mutex_exit(&port->fp_mutex);
3935
3936 return (pd);
3937 }
3938
3939 #endif /* __lock_lint */
3940
3941 /*
3942 * Looks in the pwwn table of the specified fc_local_port_t for the
3943 * fc_remote_port_t that matches the given pwwn. Hashes based upon the
3944 * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct,
3945 * but does not update any reference counts or otherwise indicate that
3946 * the fc_remote_port_t is in use.
3947 */
3948 fc_remote_port_t *
3949 fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
3950 {
3951 int index;
3952 struct pwwn_hash *head;
3953 fc_remote_port_t *pd;
3954
3955 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3956
3957 mutex_enter(&port->fp_mutex);
3958
3959 index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
3960 head = &port->fp_pwwn_table[index];
4289 mutex_exit(&port->fp_mutex);
4290 }
4291
4292
4293 job_request_t *
4294 fctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t),
4295 opaque_t arg, int sleep)
4296 {
4297 job_request_t *job;
4298
4299 job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep);
4300 if (job != NULL) {
4301 job->job_result = FC_SUCCESS;
4302 job->job_code = job_code;
4303 job->job_flags = job_flags;
4304 job->job_cb_arg = arg;
4305 job->job_comp = comp;
4306 job->job_private = NULL;
4307 job->job_ulp_pkts = NULL;
4308 job->job_ulp_listlen = 0;
4309 #ifndef __lock_lint
4310 job->job_counter = 0;
4311 job->job_next = NULL;
4312 #endif /* __lock_lint */
4313 }
4314
4315 return (job);
4316 }
4317
4318
4319 void
4320 fctl_dealloc_job(job_request_t *job)
4321 {
4322 kmem_cache_free(fctl_job_cache, (void *)job);
4323 }
4324
4325
4326 void
4327 fctl_enque_job(fc_local_port_t *port, job_request_t *job)
4328 {
4329 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4330
4331 mutex_enter(&port->fp_mutex);
4332
|
125 /*
126 * The fctl_mod_ports_lock protects the mod_ports element in the
127 * fc_ulp_ports_t structure
128 */
129
130 static krwlock_t fctl_mod_ports_lock;
131
132 /*
133 * fctl_port_lock protects the linked list of local port structures
134 * (fctl_fca_portlist). When walking the list, this lock must be obtained
135 * prior to any local port locks.
136 */
137
138 static kmutex_t fctl_port_lock;
139 static kmutex_t fctl_ulp_list_mutex;
140
141 static fctl_nwwn_list_t *fctl_nwwn_hash_table;
142 static kmutex_t fctl_nwwn_hash_mutex;
143 int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE;
144
145 #define FCTL_VERSION "20090729-1.70"
146 #define FCTL_NAME_VERSION "SunFC Transport v" FCTL_VERSION
147
148 char *fctl_version = FCTL_NAME_VERSION;
149
150 extern struct mod_ops mod_miscops;
151
152 static struct modlmisc modlmisc = {
153 &mod_miscops, /* type of module */
154 FCTL_NAME_VERSION /* Module name */
155 };
156
157 static struct modlinkage modlinkage = {
158 MODREV_1, (void *)&modlmisc, NULL
159 };
160
161 static struct bus_ops fctl_fca_busops = {
162 BUSO_REV,
163 nullbusmap, /* bus_map */
164 NULL, /* bus_get_intrspec */
1888
1889 if (pd) {
1890 mutex_enter(&pd->pd_mutex);
1891 pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN;
1892 mutex_exit(&pd->pd_mutex);
1893 }
1894 }
1895
1896
1897 /*
1898 * fc_fca_init
1899 * Overload the FCA bus_ops vector in its dev_ops with
1900 * fctl_fca_busops to handle all the INITchilds for "sf"
1901 * in one common place.
1902 *
1903 * Should be called from FCA _init routine.
1904 */
1905 void
1906 fc_fca_init(struct dev_ops *fca_devops_p)
1907 {
1908 fca_devops_p->devo_bus_ops = &fctl_fca_busops;
1909 }
1910
1911
1912 /*
1913 * fc_fca_attach
1914 */
1915 int
1916 fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran)
1917 {
1918 /*
1919 * When we are in a position to offer downward compatibility
1920 * we should change the following check to allow lower revision
1921 * of FCAs; But we aren't there right now.
1922 */
1923 if (tran->fca_version != FCTL_FCA_MODREV_5) {
1924 const char *name = ddi_driver_name(fca_dip);
1925
1926 ASSERT(name != NULL);
1927
1928 cmn_err(CE_WARN, "fctl: FCA %s version mismatch"
2413 }
2414
2415
2416 void
2417 fctl_remove_port(fc_local_port_t *port)
2418 {
2419 fc_ulp_module_t *mod;
2420 fc_fca_port_t *prev;
2421 fc_fca_port_t *list;
2422 fc_ulp_ports_t *ulp_port;
2423
2424 rw_enter(&fctl_ulp_lock, RW_WRITER);
2425 rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2426
2427 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2428 ulp_port = fctl_get_ulp_port(mod, port);
2429 if (ulp_port == NULL) {
2430 continue;
2431 }
2432
2433 ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0);
2434
2435 (void) fctl_remove_ulp_port(mod, port);
2436 }
2437
2438 rw_exit(&fctl_mod_ports_lock);
2439 rw_exit(&fctl_ulp_lock);
2440
2441 mutex_enter(&fctl_port_lock);
2442
2443 list = fctl_fca_portlist;
2444 prev = NULL;
2445 while (list != NULL) {
2446 if (list->port_handle == port) {
2447 if (prev == NULL) {
2448 fctl_fca_portlist = list->port_next;
2449 } else {
2450 prev->port_next = list->port_next;
2451 }
2452 kmem_free(list, sizeof (*list));
2453 break;
3850 head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3851
3852 pd = head->d_id_head;
3853 while (pd != NULL) {
3854 mutex_enter(&pd->pd_mutex);
3855 if (pd->pd_port_id.port_id == d_id) {
3856 /* Match found -- break out of the loop */
3857 mutex_exit(&pd->pd_mutex);
3858 break;
3859 }
3860 mutex_exit(&pd->pd_mutex);
3861 pd = pd->pd_did_hnext;
3862 }
3863
3864 mutex_exit(&port->fp_mutex);
3865
3866 return (pd);
3867 }
3868
3869
3870 void
3871 fc_ulp_hold_remote_port(opaque_t port_handle)
3872 {
3873 fc_remote_port_t *pd = port_handle;
3874
3875 mutex_enter(&pd->pd_mutex);
3876 pd->pd_ref_count++;
3877 mutex_exit(&pd->pd_mutex);
3878 }
3879
3880 /*
3881 * Looks in the d_id table of the specified fc_local_port_t for the
3882 * fc_remote_port_t that matches the given d_id. Hashes based upon
3883 * the given d_id. Returns a pointer to the fc_remote_port_t struct.
3884 *
3885 * Increments pd_ref_count in the fc_remote_port_t if the
3886 * fc_remote_port_t is found at the given d_id.
3887 *
3888 * The fc_remote_port_t is ignored (treated as non-existent) if either
3889 * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
3902
3903 pd = head->d_id_head;
3904 while (pd != NULL) {
3905 mutex_enter(&pd->pd_mutex);
3906 if (pd->pd_port_id.port_id == d_id && pd->pd_state !=
3907 PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) {
3908 ASSERT(pd->pd_ref_count >= 0);
3909 pd->pd_ref_count++;
3910 mutex_exit(&pd->pd_mutex);
3911 break;
3912 }
3913 mutex_exit(&pd->pd_mutex);
3914 pd = pd->pd_did_hnext;
3915 }
3916
3917 mutex_exit(&port->fp_mutex);
3918
3919 return (pd);
3920 }
3921
3922 /*
3923 * Looks in the pwwn table of the specified fc_local_port_t for the
3924 * fc_remote_port_t that matches the given pwwn. Hashes based upon the
3925 * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct,
3926 * but does not update any reference counts or otherwise indicate that
3927 * the fc_remote_port_t is in use.
3928 */
3929 fc_remote_port_t *
3930 fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
3931 {
3932 int index;
3933 struct pwwn_hash *head;
3934 fc_remote_port_t *pd;
3935
3936 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3937
3938 mutex_enter(&port->fp_mutex);
3939
3940 index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
3941 head = &port->fp_pwwn_table[index];
4270 mutex_exit(&port->fp_mutex);
4271 }
4272
4273
4274 job_request_t *
4275 fctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t),
4276 opaque_t arg, int sleep)
4277 {
4278 job_request_t *job;
4279
4280 job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep);
4281 if (job != NULL) {
4282 job->job_result = FC_SUCCESS;
4283 job->job_code = job_code;
4284 job->job_flags = job_flags;
4285 job->job_cb_arg = arg;
4286 job->job_comp = comp;
4287 job->job_private = NULL;
4288 job->job_ulp_pkts = NULL;
4289 job->job_ulp_listlen = 0;
4290 job->job_counter = 0;
4291 job->job_next = NULL;
4292 }
4293
4294 return (job);
4295 }
4296
4297
4298 void
4299 fctl_dealloc_job(job_request_t *job)
4300 {
4301 kmem_cache_free(fctl_job_cache, (void *)job);
4302 }
4303
4304
4305 void
4306 fctl_enque_job(fc_local_port_t *port, job_request_t *job)
4307 {
4308 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4309
4310 mutex_enter(&port->fp_mutex);
4311
|