📄 qla_rscn.c
字号:
* to login to a remote port with just * a loop id without knowing about the * port id. Copy the port id and try * again. */ remote_fcport->d_id.b24 = inuse_did.b24; iodesc->d_id.b24 = inuse_did.b24; } else { remote_fcport->loop_id++; rval = qla2x00_find_new_loop_id(ha, remote_fcport); if (rval == QLA_FUNCTION_FAILED) { /* No more loop ids. */ return (QLA_SUCCESS); } } } else if (mb[0] == MBS_PORT_ID_USED) { /* * Device has another loop ID. The firmware * group recommends the driver perform an * implicit login with the specified ID. */ DEBUG14(printk("scsi(%ld): Login IOCB -- port " "id [%02x%02x%02x] already assigned to " "loop id [%x].\n", ha->host_no, iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa, mb[1])); remote_fcport->loop_id = mb[1]; } else { /* Unable to perform login, try again. */ DEBUG14(printk("scsi(%ld): Login IOCB -- " "failed login [%x/%02x%02x%02x], status=%x " "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", ha->host_no, remote_fcport->loop_id, iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa, status, mb[0], mb[1], mb[2], mb[6], mb[7])); } /* Reissue Login with the same IO descriptor. */ iodesc->signature = qla2x00_iodesc_to_handle(iodesc); iodesc->cb_idx = LOGIN_PORT_IOCB_CB; iodesc->d_id.b24 = remote_fcport->d_id.b24; remote_fcport->iodesc_idx_sent = iodesc->idx; remote_fcport->login_retry--; DEBUG14(printk("scsi(%ld): Login IOCB -- retrying " "login to [%x/%02x%02x%02x] (%d).\n", ha->host_no, remote_fcport->loop_id, remote_fcport->d_id.b.domain, remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa, remote_fcport->login_retry)); qla2x00_send_login_iocb(ha, iodesc, &remote_fcport->d_id, 1); return (QLA_FUNCTION_FAILED); } else { /* No more logins, mark device dead. */ DEBUG14(printk("scsi(%ld): Login IOCB -- failed " "login [%x/%02x%02x%02x] after retries, status=%x " "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", ha->host_no, remote_fcport->loop_id, iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa, status, mb[0], mb[1], mb[2], mb[6], mb[7])); atomic_set(&remote_fcport->state, FCS_DEVICE_DEAD); if (remote_fcport->port_type == FCT_RSCN) { DEBUG14(printk("scsi(%ld): Login IOCB -- " "Freeing dead RSCN fcport %p " "[%x/%02x%02x%02x].\n", ha->host_no, remote_fcport, remote_fcport->loop_id, remote_fcport->d_id.b.domain, remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa)); list_del(&remote_fcport->list); kfree(remote_fcport); } } } return (QLA_SUCCESS);}/** * IO descriptor processing routines. **//** * qla2x00_alloc_rscn_fcport() - Allocate an RSCN type fcport. * @ha: HA context * @flags: allocation flags * * Returns a pointer to the allocated RSCN fcport, or NULL, if none available. */fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, gfp_t flags){ fc_port_t *fcport; fcport = qla2x00_alloc_fcport(ha, flags); if (fcport == NULL) return (fcport); /* Setup RSCN fcport structure. */ fcport->port_type = FCT_RSCN; return (fcport);}/** * qla2x00_handle_port_rscn() - Handle port RSCN. * @ha: HA context * @rscn_entry: RSCN entry * @fcport: fcport entry to updated * * Returns QLA_SUCCESS if the port RSCN was handled. */intqla2x00_handle_port_rscn(scsi_qla_host_t *ha, uint32_t rscn_entry, fc_port_t *known_fcport, int ha_locked){ int rval; port_id_t rscn_pid; fc_port_t *fcport, *remote_fcport, *rscn_fcport; struct io_descriptor *iodesc; remote_fcport = NULL; rscn_fcport = NULL; /* Prepare port id based on incoming entries. */ if (known_fcport) { rscn_pid.b24 = known_fcport->d_id.b24; remote_fcport = known_fcport; DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for " "fcport [%02x%02x%02x].\n", ha->host_no, remote_fcport->d_id.b.domain, remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa)); } else { rscn_pid.b.domain = LSB(MSW(rscn_entry)); rscn_pid.b.area = MSB(LSW(rscn_entry)); rscn_pid.b.al_pa = LSB(LSW(rscn_entry)); DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for " "port id [%02x%02x%02x].\n", ha->host_no, rscn_pid.b.domain, rscn_pid.b.area, rscn_pid.b.al_pa)); /* * Search fcport lists for a known entry at the specified port * ID. */ list_for_each_entry(fcport, &ha->fcports, list) { if (rscn_pid.b24 == fcport->d_id.b24) { remote_fcport = fcport; break; } } list_for_each_entry(fcport, &ha->rscn_fcports, list) { if (rscn_pid.b24 == fcport->d_id.b24) { rscn_fcport = fcport; break; } } if (remote_fcport == NULL) remote_fcport = rscn_fcport; } /* * If the port is already in our fcport list and online, send an ADISC * to see if it's still alive. Issue login if a new fcport or the known * fcport is currently offline. */ if (remote_fcport) { /* * No need to send request if the remote fcport is currently * waiting for an available io descriptor. */ if (known_fcport == NULL && (remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED || remote_fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED)) { /* * If previous waiting io descriptor is an ADISC, then * the new RSCN may come from a new remote fcport being * plugged into the same location. */ if (remote_fcport->port_type == FCT_RSCN) { remote_fcport->iodesc_idx_sent = IODESC_LOGIN_NEEDED; } else if (remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED) { fc_port_t *new_fcport; remote_fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; /* Create new fcport for later login. */ new_fcport = qla2x00_alloc_rscn_fcport(ha, ha_locked ? GFP_ATOMIC: GFP_KERNEL); if (new_fcport) { DEBUG14(printk("scsi(%ld): Handle RSCN " "-- creating RSCN fcport %p for " "future login.\n", ha->host_no, new_fcport)); new_fcport->d_id.b24 = remote_fcport->d_id.b24; new_fcport->iodesc_idx_sent = IODESC_LOGIN_NEEDED; list_add_tail(&new_fcport->list, &ha->rscn_fcports); set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags); } else { DEBUG14(printk("scsi(%ld): Handle RSCN " "-- unable to allocate RSCN fcport " "for future login.\n", ha->host_no)); } } return (QLA_SUCCESS); } /* Send ADISC if the fcport is online */ if (atomic_read(&remote_fcport->state) == FCS_ONLINE || remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED) { atomic_set(&remote_fcport->state, FCS_DEVICE_LOST); iodesc = qla2x00_alloc_iodesc(ha); if (iodesc == NULL) { /* Mark fcport for later adisc processing */ DEBUG14(printk("scsi(%ld): Handle RSCN -- not " "enough IO descriptors for Adisc, flag " "for later processing.\n", ha->host_no)); remote_fcport->iodesc_idx_sent = IODESC_ADISC_NEEDED; set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags); return (QLA_SUCCESS); } iodesc->cb_idx = ADISC_PORT_IOCB_CB; iodesc->d_id.b24 = rscn_pid.b24; iodesc->remote_fcport = remote_fcport; remote_fcport->iodesc_idx_sent = iodesc->idx; qla2x00_send_adisc_iocb(ha, iodesc, ha_locked); return (QLA_SUCCESS); } else if (remote_fcport->iodesc_idx_sent < MAX_IO_DESCRIPTORS && ha->io_descriptors[remote_fcport->iodesc_idx_sent].cb_idx == ADISC_PORT_IOCB_CB) { /* * Receiving another RSCN while an ADISC is pending, * abort the IOCB. Use the same descriptor for the * abort. */ uint32_t handle_to_abort; iodesc = &ha->io_descriptors[ remote_fcport->iodesc_idx_sent]; qla2x00_remove_iodesc_timer(iodesc); handle_to_abort = iodesc->signature; iodesc->signature = qla2x00_iodesc_to_handle(iodesc); iodesc->cb_idx = ABORT_IOCB_CB; iodesc->d_id.b24 = remote_fcport->d_id.b24; iodesc->remote_fcport = remote_fcport; remote_fcport->iodesc_idx_sent = iodesc->idx; DEBUG14(printk("scsi(%ld): Handle RSCN -- issuing " "abort to outstanding Adisc [%x/%02x%02x%02x].\n", ha->host_no, remote_fcport->loop_id, iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa)); qla2x00_send_abort_iocb(ha, iodesc, handle_to_abort, ha_locked); } } /* We need to login to the remote port, find it. */ if (known_fcport) { remote_fcport = known_fcport; } else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID && rscn_fcport->iodesc_idx_sent < MAX_IO_DESCRIPTORS && ha->io_descriptors[rscn_fcport->iodesc_idx_sent].cb_idx == LOGIN_PORT_IOCB_CB) { /* * Ignore duplicate RSCN on fcport which has already * initiated a login IOCB. */ DEBUG14(printk("scsi(%ld): Handle RSCN -- ignoring, login " "already sent to [%02x%02x%02x].\n", ha->host_no, rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area, rscn_fcport->d_id.b.al_pa)); return (QLA_SUCCESS); } else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID && rscn_fcport != remote_fcport) { /* Reuse same rscn fcport. */ DEBUG14(printk("scsi(%ld): Handle RSCN -- reusing RSCN fcport " "[%02x%02x%02x].\n", ha->host_no, rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area, rscn_fcport->d_id.b.al_pa)); remote_fcport = rscn_fcport; } else { /* Create new fcport for later login. */ remote_fcport = qla2x00_alloc_rscn_fcport(ha, ha_locked ? GFP_ATOMIC: GFP_KERNEL); list_add_tail(&remote_fcport->list, &ha->rscn_fcports); } if (remote_fcport == NULL) return (QLA_SUCCESS); /* Prepare fcport for login. */ atomic_set(&remote_fcport->state, FCS_DEVICE_LOST); remote_fcport->login_retry = 3; /* ha->login_retry_count; */ remote_fcport->d_id.b24 = rscn_pid.b24; iodesc = qla2x00_alloc_iodesc(ha); if (iodesc == NULL) { /* Mark fcport for later adisc processing. */ DEBUG14(printk("scsi(%ld): Handle RSCN -- not enough IO " "descriptors for Login, flag for later processing.\n", ha->host_no)); remote_fcport->iodesc_idx_sent = IODESC_LOGIN_NEEDED; set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags); return (QLA_SUCCESS); } if (known_fcport == NULL || rscn_pid.b24 != INVALID_PORT_ID) { remote_fcport->loop_id = ha->min_external_loopid; rval = qla2x00_find_new_loop_id(ha, remote_fcport); if (rval == QLA_FUNCTION_FAILED) { /* No more loop ids, failed. */ DEBUG14(printk("scsi(%ld): Handle RSCN -- no available " "loop id to perform Login, failed.\n", ha->host_no)); return (rval); } } iodesc->cb_idx = LOGIN_PORT_IOCB_CB; iodesc->d_id.b24 = rscn_pid.b24; iodesc->remote_fcport = remote_fcport; remote_fcport->iodesc_idx_sent = iodesc->idx; DEBUG14(printk("scsi(%ld): Handle RSCN -- attempting login to " "[%x/%02x%02x%02x].\n", ha->host_no, remote_fcport->loop_id, iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa)); qla2x00_send_login_iocb(ha, iodesc, &rscn_pid, ha_locked); return (QLA_SUCCESS);}/** * qla2x00_process_iodesc() - Complete IO descriptor processing. * @ha: HA context * @mbxstat: Mailbox IOCB status */voidqla2x00_process_iodesc(scsi_qla_host_t *ha, struct mbx_entry *mbxstat){ int rval; uint32_t signature; fc_port_t *fcport; struct io_descriptor *iodesc; signature = mbxstat->handle; DEBUG14(printk("scsi(%ld): Process IODesc -- processing %08x.\n", ha->host_no, signature)); /* Retrieve proper IO descriptor. */ iodesc = qla2x00_handle_to_iodesc(ha, signature); if (iodesc == NULL) { DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, " "incorrect signature %08x.\n", ha->host_no, signature)); return; } /* Stop IO descriptor timer. */ qla2x00_remove_iodesc_timer(iodesc); /* Verify signature match. */ if (iodesc->signature != signature) { DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, " "signature mismatch, sent %08x, received %08x.\n", ha->host_no, iodesc->signature, signature)); return; } /* Go with IOCB callback. */ rval = iocb_function_cb_list[iodesc->cb_idx](ha, iodesc, mbxstat); if (rval != QLA_SUCCESS) { /* IO descriptor reused by callback. */ return; } qla2x00_free_iodesc(iodesc); if (test_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags)) { /* Scan our fcports list for any RSCN requests. */ list_for_each_entry(fcport, &ha->fcports, list) { if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED || fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) { qla2x00_handle_port_rscn(ha, 0, fcport, 1); return; } } /* Scan our RSCN fcports list for any RSCN requests. */ list_for_each_entry(fcport, &ha->rscn_fcports, list) { if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED || fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) { qla2x00_handle_port_rscn(ha, 0, fcport, 1); return; } } } clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);}/** * qla2x00_cancel_io_descriptors() - Cancel all outstanding io descriptors. * @ha: HA context * * This routine will also delete any RSCN entries related to the outstanding * IO descriptors. */voidqla2x00_cancel_io_descriptors(scsi_qla_host_t *ha){ fc_port_t *fcport, *fcptemp; clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags); /* Abort all IO descriptors. */ qla2x00_init_io_descriptors(ha); /* Reset all pending IO descriptors in fcports list. */ list_for_each_entry(fcport, &ha->fcports, list) { fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; } /* Reset all pending IO descriptors in rscn fcports list. */ list_for_each_entry_safe(fcport, fcptemp, &ha->rscn_fcports, list) { DEBUG14(printk("scsi(%ld): Cancel IOs -- Freeing RSCN fcport " "%p [%x/%02x%02x%02x].\n", ha->host_no, fcport, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa)); list_del(&fcport->list); kfree(fcport); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -