📄 iph5526.c
字号:
* that has been allocated for SCSI, will be called a Bad * SCSI frame if the Exchange is not valid any more. * * We will also get a Bad SCSI frame interrupt if we receive * a XFER_RDY with offset != 0. Tachyon washes its hands off * this Exchange. We have to take care of ourselves. Grrr... */ if (rctl == DATA_DESCRIPTOR) { struct fc_node_info *q = fi->node_info_list; while (q != NULL) { if (q->d_id == s_id) { target_id = q->target_id; mtu = q->mtu; break; } else q = q->next; } frame_class = target_id; transfered_len = ntohl(*(buff_addr + 8)); burst_len = ntohl(*(buff_addr + 9)); build_ODB(fi, fi->g.seq_id, s_id, burst_len, 0, mtu, ox_id, rx_id, 0, 0, frame_class << 16); /* Update the SEQ_ID and Relative Offset in the * Tachyon Header Structure. */ tach_header = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 5))); *(tach_header + 5) = htonl(fi->g.seq_id << 24); *(tach_header + 7) = htonl(transfered_len); fi->g.odb.hdr_addr = *(fi->q.ptr_sest[x_id] + 5); /* Invalidate the EDBs used */ ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7))); for (i = 0; i < EDB_LEN; i++) if (fi->q.ptr_edb[i] == ptr_edb) break; ptr_edb--; if (i < EDB_LEN) { int j; do { ptr_edb += 2; len += (htonl(*ptr_edb) & 0xFFFF); j = i; fi->q.free_edb_list[i++] = EDB_FREE; if (i == EDB_LEN) { i = 0; ptr_edb = fi->q.ptr_edb_base - 1; } } while (len < transfered_len); if (len > transfered_len) { ptr_edb--; fi->q.free_edb_list[j] = EDB_BUSY; } else ptr_edb++; } else { T_MSG("EDB not found while freeing"); if (offset == (NO_OF_ENTRIES - 1)) update_SFSBQ_indx(fi); return; } /* Update the EDB pointer in the ODB. */ fi->g.odb.edb_addr = htonl(virt_to_bus(ptr_edb)); memcpy(fi->q.ptr_odb[fi->q.ocq_prod_indx], &(fi->g.odb), sizeof(ODB)); /* Update the EDB pointer in the SEST entry. We might need * this if get another XFER_RDY for the same Exchange. */ *(fi->q.ptr_sest[x_id] + 7) = htonl(virt_to_bus(ptr_edb)); update_OCQ_indx(fi); if (fi->g.seq_id == MAX_SEQ_ID) fi->g.seq_id = 0; else fi->g.seq_id++; } else /* Could be a BA_ACC or a BA_RJT. */ if (rctl == RCTL_BASIC_ACC) { u_int bls_type = remove_from_ox_id_list(fi, ox_id); DPRINTK1("BA_ACC received from S_ID 0x%x with OX_ID = %x in response to %x", s_id, ox_id, bls_type); if (bls_type == RCTL_BASIC_ABTS) { u_int STE_bit; /* Invalidate resources for that Exchange. */ STE_bit = ntohl(*fi->q.ptr_sest[x_id]); if (STE_bit & SEST_V) { *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV); invalidate_SEST_entry(fi, ox_id); } } } else if (rctl == RCTL_BASIC_RJT) { u_int bls_type = remove_from_ox_id_list(fi, ox_id); DPRINTK1("BA_RJT received from S_ID 0x%x with OX_ID = %x in response to %x", s_id, ox_id, bls_type); if (bls_type == RCTL_BASIC_ABTS) { u_int STE_bit; /* Invalidate resources for that Exchange. */ STE_bit = ntohl(*fi->q.ptr_sest[x_id]); if (STE_bit & SEST_V) { *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV); invalidate_SEST_entry(fi, ox_id); } } } else DPRINTK1("Frame with R_CTL = %x received from S_ID 0x%x with OX_ID %x", rctl, s_id, ox_id); /* Else, discard the "Bad" SCSI frame. */ /* provide Tachyon will another set of buffers */ if (offset == (NO_OF_ENTRIES - 1)) update_SFSBQ_indx(fi); LEAVE("handle_Bad_SCSI_Frame_interrupt");}static void handle_Inbound_SCSI_Status_interrupt(struct fc_info *fi){struct Scsi_Host *host = fi->host;struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;u_int *ptr_imq_entry, *buff_addr, *ptr_rsp_info, *ptr_sense_info = NULL;int queue_indx, offset, payload_size;u_short received_ox_id, x_id;Scsi_Cmnd *Cmnd;u_int fcp_status, fcp_rsp_info_len = 0, fcp_sense_info_len = 0, s_id; ENTER("handle_SCSI_status_interrupt"); ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; queue_indx = queue_indx >> 16; buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset))); payload_size = ntohl(*(ptr_imq_entry + 2)); received_ox_id = ntohl(*(buff_addr + 6)) >> 16; buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset))); fcp_status = ntohl(*(buff_addr + 10)); ptr_rsp_info = buff_addr + 14; if (fcp_status & FCP_STATUS_RSP_LEN) fcp_rsp_info_len = ntohl(*(buff_addr + 13)); if (fcp_status & FCP_STATUS_SENSE_LEN) { ptr_sense_info = ptr_rsp_info + fcp_rsp_info_len / 4; fcp_sense_info_len = ntohl(*(buff_addr + 12)); DPRINTK("sense_info = %x", (u_int)ntohl(*ptr_sense_info)); } DPRINTK("fcp_status = %x, fcp_rsp_len = %x", fcp_status, fcp_rsp_info_len); x_id = received_ox_id & MAX_SCSI_XID; Cmnd = hostdata->cmnd_handler[x_id]; hostdata->cmnd_handler[x_id] = NULL; if (Cmnd != NULL) { memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer)); /* Check if there is a Sense field */ if (fcp_status & FCP_STATUS_SENSE_LEN) { int size = sizeof(Cmnd->sense_buffer); if (fcp_sense_info_len < size) size = fcp_sense_info_len; memcpy(Cmnd->sense_buffer, (char *)ptr_sense_info, size); } Cmnd->result = fcp_status & FCP_STATUS_MASK; (*Cmnd->scsi_done) (Cmnd); } else T_MSG("NULL Command out of handler!"); invalidate_SEST_entry(fi, received_ox_id); s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF; fi->q.free_scsi_oxid[x_id] = OXID_AVAILABLE; /* provide Tachyon will another set of buffers */ if (offset == (NO_OF_ENTRIES - 1)) update_SFSBQ_indx(fi); LEAVE("handle_SCSI_status_interrupt");}static void invalidate_SEST_entry(struct fc_info *fi, u_short received_ox_id){u_short x_id = received_ox_id & MAX_SCSI_XID; /* Invalidate SEST entry if it is an OutBound SEST Entry */ if (!(received_ox_id & SCSI_READ_BIT)) { u_int *ptr_tach_header, *ptr_edb; u_short temp_ox_id = NOT_SCSI_XID; int i; *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV); /* Invalidate the Tachyon Header structure */ ptr_tach_header = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 5))); for (i = 0; i < NO_OF_TACH_HEADERS; i++) if(fi->q.ptr_tachyon_header[i] == ptr_tach_header) break; if (i < NO_OF_TACH_HEADERS) memset(ptr_tach_header, 0xFF, 32); else T_MSG("Tachyon Header not found while freeing in invalidate_SEST_entry()"); /* Invalidate the EDB used */ ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7))); for (i = 0; i < EDB_LEN; i++) if (fi->q.ptr_edb[i] == ptr_edb) break; ptr_edb--; if (i < EDB_LEN) { do { ptr_edb += 2; fi->q.free_edb_list[i++] = EDB_FREE; if (i == EDB_LEN) { i = 0; ptr_edb = fi->q.ptr_edb_base - 1; } } while ((htonl(*ptr_edb) & 0x80000000) != 0x80000000); } else T_MSG("EDB not found while freeing in invalidate_SEST_entry()"); /* Search for its other header structure and destroy it! */ if ((ptr_tach_header + 16) < (fi->q.ptr_tachyon_header_base + (MY_PAGE_SIZE/4))) ptr_tach_header += 16; else ptr_tach_header = fi->q.ptr_tachyon_header_base; while (temp_ox_id != x_id) { temp_ox_id = ntohl(*(ptr_tach_header + 6)) >> 16; if (temp_ox_id == x_id) { /* Paranoid checking... */ for (i = 0; i < NO_OF_TACH_HEADERS; i++) if(fi->q.ptr_tachyon_header[i] == ptr_tach_header) break; if (i < NO_OF_TACH_HEADERS) memset(ptr_tach_header, 0xFF, 32); else T_MSG("Tachyon Header not found while freeing in invalidate_SEST_entry()"); break; } else { if ((ptr_tach_header + 16) < (fi->q.ptr_tachyon_header_base + (MY_PAGE_SIZE/4))) ptr_tach_header += 16; else ptr_tach_header = fi->q.ptr_tachyon_header_base; } } } else { u_short sdb_table_indx; /* An Inbound Command has completed or needs to be Aborted. * Clear up the SDB buffers. */ sdb_table_indx = *(fi->q.ptr_sest[x_id] + 5); fi->q.sdb_slot_status[sdb_table_indx] = SDB_FREE; }}static void handle_Inbound_SCSI_Command_interrupt(struct fc_info *fi){u_int *ptr_imq_entry;int queue_indx, offset; ENTER("handle_Inbound_SCSI_Command_interrupt"); ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; queue_indx = queue_indx >> 16; /* We discard the SCSI frame as we shouldn't be receiving * a SCSI Command in the first place */ /* provide Tachyon will another set of buffers */ if (offset == (NO_OF_ENTRIES - 1)) update_SFSBQ_indx(fi); LEAVE("handle_Inbound_SCSI_Command_interrupt");}static void handle_SFS_interrupt(struct fc_info *fi){u_int *ptr_imq_entry, *buff_addr;u_int class_of_frame, type_of_frame, s_id, els_type = 0, rctl;int queue_indx, offset, payload_size, login_state;u_short received_ox_id, fs_cmnd_code; ENTER("handle_SFS_interrupt"); ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx]; offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007; queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000; queue_indx = queue_indx >> 16; DPRINTK("queue_indx = %d, offset = %d\n", queue_indx, offset); payload_size = ntohl(*(ptr_imq_entry + 2)); DPRINTK("payload_size = %d", payload_size); buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset))); /* extract Type of Frame */ type_of_frame = ntohl(*(buff_addr + 4)) & 0xFF000000; s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF; received_ox_id = ntohl(*(buff_addr + 6)) >> 16; switch(type_of_frame) { case TYPE_BLS: rctl = ntohl(*(buff_addr + 2)) & 0xFF000000; switch(rctl) { case RCTL_BASIC_ABTS: /* As an Initiator, we should never be receiving * this. */ DPRINTK1("ABTS received from S_ID 0x%x with OX_ID = %x", s_id, received_ox_id); break; } break; case TYPE_ELS: class_of_frame = ntohl(*(buff_addr + 8)); login_state = sid_logged_in(fi, s_id); switch(class_of_frame & 0xFF000000) { case ELS_PLOGI: if (s_id != fi->g.my_id) { u_int ret_code; DPRINTK1("PLOGI received from D_ID 0x%x with 0X_ID = %x", s_id, received_ox_id); if ((ret_code = plogi_ok(fi, buff_addr, payload_size)) == 0){ tx_logi_acc(fi, ELS_ACC, s_id, received_ox_id); add_to_address_cache(fi, buff_addr); } else { u_short cmnd_code = ret_code >> 16; u_short expln_code = ret_code; tx_ls_rjt(fi, s_id, received_ox_id, cmnd_code, expln_code); } } break; case ELS_ACC: els_type = remove_from_ox_id_list(fi, received_ox_id); DPRINTK1("ELS_ACC received from D_ID 0x%x in response to ELS %x", s_id, els_type); switch(els_type) { case ELS_PLOGI: add_to_address_cache(fi, buff_addr); tx_prli(fi, ELS_PRLI, s_id, OX_ID_FIRST_SEQUENCE); break; case ELS_FLOGI: add_to_address_cache(fi, buff_addr); fi->g.my_id = ntohl(*(buff_addr + 2)) & 0x00FFFFFF; fi->g.fabric_present = TRUE; fi->g.my_ddaa = fi->g.my_id & 0xFFFF00; /* Login to the Name Server */ tx_logi(fi, ELS_PLOGI, DIRECTORY_SERVER); break; case ELS_NS_PLOGI: fi->g.name_server = TRUE; add_to_address_cache(fi, buff_addr); tx_name_server_req(fi, FCS_RFC_4); tx_scr(fi); /* Some devices have a delay before * registering with the Name Server */ udelay(500); tx_name_server_req(fi, FCS_GP_ID4); break; case ELS_PRLI: mark_scsi_sid(fi, buff_addr, ADD_ENTRY); break; case ELS_ADISC: if (!(validate_login(fi, buff_addr))) tx_logo(fi, s_id, OX_ID_FIRST_SEQUENCE); break; } break; case ELS_PDISC: DPRINTK1("ELS_PDISC received from D_ID 0x%x", s_id); tx_logo(fi, s_id, received_ox_id); break; case ELS_ADISC: DPRINTK1("ELS_ADISC received from D_ID 0x%x", s_id); if (node_logged_in_prev(fi, buff_addr)) tx_adisc(fi, ELS_ACC, s_id, received_ox_id); else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -