?? fc.c
字號:
fcp_cmnd *fcmd; fcp_rsp *rsp; int host_status; Scsi_Cmnd *SCpnt; int sense_len; int rsp_status; fcmd = fc->cmd_slots[token]; if (!fcmd) return; rsp = (fcp_rsp *) (fc->scsi_rsp_pool + fc->rsp_size * token); SCpnt = SC_FCMND(fcmd); if (SCpnt->done != fcp_scsi_done) return; rsp_status = rsp->fcp_status; FCD(("rsp_status %08x status %08x\n", rsp_status, status)) switch (status) { case FC_STATUS_OK: host_status=DID_OK; if (rsp_status & FCP_STATUS_RESID) {#ifdef FCDEBUG FCD(("Resid %d\n", rsp->fcp_resid)) { fcp_cmd *cmd = fc->scsi_cmd_pool + token; int i; printk ("Command "); for (i = 0; i < sizeof(fcp_cmd); i+=4) printk ("%08x ", *(u32 *)(((char *)cmd)+i)); printk ("\nResponse "); for (i = 0; i < fc->rsp_size; i+=4) printk ("%08x ", *(u32 *)(((char *)rsp)+i)); printk ("\n"); }#endif } if (rsp_status & FCP_STATUS_SENSE_LEN) { sense_len = rsp->fcp_sense_len; if (sense_len > sizeof(SCpnt->sense_buffer)) sense_len = sizeof(SCpnt->sense_buffer); memcpy(SCpnt->sense_buffer, ((char *)(rsp+1)), sense_len); } if (fcmd->data) { if (SCpnt->use_sg) dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->buffer, SCpnt->use_sg, scsi_to_fc_dma_dir(SCpnt->sc_data_direction)); else dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen, scsi_to_fc_dma_dir(SCpnt->sc_data_direction)); } break; default: host_status=DID_ERROR; /* FIXME */ FCD(("Wrong FC status %d for token %d\n", status, token)) break; } if (status_byte(rsp_status) == QUEUE_FULL) { printk ("%s: (%d,%d) Received rsp_status 0x%x\n", fc->name, SCpnt->channel, SCpnt->target, rsp_status); } SCpnt->result = (host_status << 16) | (rsp_status & 0xff);#ifdef FCDEBUG if (host_status || SCpnt->result || rsp_status) printk("FC: host_status %d, packet status %d\n", host_status, SCpnt->result);#endif SCpnt->done = fcmd->done; fcmd->done=NULL; clear_bit(token, fc->scsi_bitmap); fc->scsi_free++; FCD(("Calling scsi_done with %08x\n", SCpnt->result)) SCpnt->scsi_done(SCpnt);}void fcp_receive_solicited(fc_channel *fc, int proto, int token, int status, fc_hdr *fch){ int magic; FCD(("receive_solicited %d %d %d\n", proto, token, status)) switch (proto) { case TYPE_SCSI_FCP: fcp_scsi_receive(fc, token, status, fch); break; case TYPE_EXTENDED_LS: case PROTO_REPORT_AL_MAP: magic = 0; if (fc->ls) magic = ((ls *)(fc->ls))->magic; if (magic == LSMAGIC) { ls *l = (ls *)fc->ls; int i = (token >= l->count) ? token - l->count : token; /* Let's be sure */ if ((unsigned)i < l->count && l->fcmds[i].fc == fc) { if (proto == TYPE_EXTENDED_LS) fcp_login_done(fc, token, status); else fcp_report_map_done(fc, token, status); break; } } FCD(("fc %p fc->ls %p fc->cmd_slots %p\n", fc, fc->ls, fc->cmd_slots)) if (proto == TYPE_EXTENDED_LS && !fc->ls && fc->cmd_slots) { fcp_cmnd *fcmd; fcmd = fc->cmd_slots[token]; if (fcmd && fcmd->ls && ((ls *)(fcmd->ls))->magic == LSEMAGIC) { lse *l = (lse *)fcmd->ls; l->status = status; up (&l->sem); } } break; case PROTO_OFFLINE: if (fc->ls && ((lso *)(fc->ls))->magic == LSOMAGIC) { lso *l = (lso *)fc->ls; if ((unsigned)token < l->count && l->fcmds[token].fc == fc) { /* Wow, OFFLINE response arrived :) */ FCD(("OFFLINE Response arrived\n")) fc->state = FC_STATE_OFFLINE; if (atomic_dec_and_test (&l->todo)) up(&l->sem); } } break; default: break; }}void fcp_state_change(fc_channel *fc, int state){ FCD(("state_change %d %d\n", state, fc->state)) if (state == FC_STATE_ONLINE && fc->state == FC_STATE_MAYBEOFFLINE) fc->state = FC_STATE_UNINITED; else if (state == FC_STATE_ONLINE) printk (KERN_WARNING "%s: state change to ONLINE\n", fc->name); else printk (KERN_ERR "%s: state change to OFFLINE\n", fc->name);}int fcp_initialize(fc_channel *fcchain, int count){ fc_channel *fc; fcp_cmnd *fcmd; int i, retry, ret; ls *l; FCND(("fcp_inititialize %08lx\n", (long)fcp_init)) FCND(("fc_channels %08lx\n", (long)fc_channels)) FCND((" SID %d DID %d\n", fcchain->sid, fcchain->did)) l = kmalloc(sizeof (ls) + count, GFP_KERNEL); if (!l) { printk ("FC: Cannot allocate memory for initialization\n"); return -ENOMEM; } memset (l, 0, sizeof(ls) + count); l->magic = LSMAGIC; l->count = count; FCND(("FCP Init for %d channels\n", count)) init_MUTEX_LOCKED(&l->sem); l->timer.function = fcp_login_timeout; l->timer.data = (unsigned long)l; atomic_set (&l->todo, count); l->logi = kmalloc (count * 3 * sizeof(logi), GFP_KERNEL); l->fcmds = kmalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); if (!l->logi || !l->fcmds) { if (l->logi) kfree (l->logi); if (l->fcmds) kfree (l->fcmds); kfree (l); printk ("FC: Cannot allocate DMA memory for initialization\n"); return -ENOMEM; } memset (l->logi, 0, count * 3 * sizeof(logi)); memset (l->fcmds, 0, count * sizeof(fcp_cmnd)); for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { fc->state = FC_STATE_UNINITED; fc->rst_pkt = NULL; /* kmalloc when first used */ } /* First try if we are in a AL topology */ FCND(("Initializing REPORT_MAP packets\n")) for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { fcmd = l->fcmds + i; fc->login = fcmd; fc->ls = (void *)l; /* Assumes sizeof(fc_al_posmap) < 3 * sizeof(logi), which is true */ fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL); fcmd->proto = PROTO_REPORT_AL_MAP; fcmd->token = i; fcmd->fc = fc; } for (retry = 0; retry < 8; retry++) { int nqueued = 0; FCND(("Sending REPORT_MAP/FLOGI/PLOGI packets\n")) for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { if (fc->state == FC_STATE_ONLINE || fc->state == FC_STATE_OFFLINE) continue; disable_irq(fc->irq); if (fc->state == FC_STATE_MAYBEOFFLINE) { if (!l->grace[i]) { l->grace[i]++; FCD(("Grace\n")) } else { fc->state = FC_STATE_OFFLINE; enable_irq(fc->irq); dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL); if (atomic_dec_and_test (&l->todo)) goto all_done; } } ret = fc->hw_enque (fc, fc->login); enable_irq(fc->irq); if (!ret) { nqueued++; continue; } if (ret == -ENOSYS && fc->login->proto == PROTO_REPORT_AL_MAP) { /* Oh yes, this card handles Point-to-Point only, so let's try that. */ fc_hdr *fch; FCD(("SID %d DID %d\n", fc->sid, fc->did)) fcmd = l->fcmds + i; dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL); fch = &fcmd->fch; FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT); FILL_FCHDR_SID(fch, 0); FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); fch->param = 0; l->logi [3 * i].code = LS_FLOGI; fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL); fcmd->rsp = fcmd->cmd + sizeof(logi); fcmd->cmdlen = sizeof(logi); fcmd->rsplen = sizeof(logi); fcmd->data = (dma_addr_t)NULL; fcmd->class = FC_CLASS_SIMPLE; fcmd->proto = TYPE_EXTENDED_LS; } else printk ("FC: Cannot enque FLOGI/REPORT_MAP packet on %s\n", fc->name); } if (nqueued) { l->timer.expires = jiffies + 5 * HZ; add_timer(&l->timer); down(&l->sem); if (!atomic_read(&l->todo)) { FCND(("All channels answered in time\n")) break; /* All fc channels have answered us */ } } }all_done: for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { fc->ls = NULL; switch (fc->state) { case FC_STATE_ONLINE: break; case FC_STATE_OFFLINE: break; default: dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL); break; } } del_timer(&l->timer); kfree (l->logi); kfree (l->fcmds); kfree (l); return 0;}int fcp_forceoffline(fc_channel *fcchain, int count){ fc_channel *fc; fcp_cmnd *fcmd; int i, ret; lso l; memset (&l, 0, sizeof(lso)); l.count = count; l.magic = LSOMAGIC; FCND(("FCP Force Offline for %d channels\n", count)) init_MUTEX_LOCKED(&l.sem); l.timer.function = fcp_login_timeout; l.timer.data = (unsigned long)&l; atomic_set (&l.todo, count); l.fcmds = kmalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); if (!l.fcmds) { kfree (l.fcmds); printk ("FC: Cannot allocate memory for forcing offline\n"); return -ENOMEM; } memset (l.fcmds, 0, count * sizeof(fcp_cmnd)); FCND(("Initializing OFFLINE packets\n")) for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { fc->state = FC_STATE_UNINITED; fcmd = l.fcmds + i; fc->login = fcmd; fc->ls = (void *)&l; fcmd->did = fc->did; fcmd->class = FC_CLASS_OFFLINE; fcmd->proto = PROTO_OFFLINE; fcmd->token = i; fcmd->fc = fc; disable_irq(fc->irq); ret = fc->hw_enque (fc, fc->login); enable_irq(fc->irq); if (ret) printk ("FC: Cannot enque OFFLINE packet on %s\n", fc->name); } l.timer.expires = jiffies + 5 * HZ; add_timer(&l.timer); down(&l.sem); del_timer(&l.timer); for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) fc->ls = NULL; kfree (l.fcmds); return 0;}int fcp_init(fc_channel *fcchain){ fc_channel *fc; int count=0; int ret; for (fc = fcchain; fc; fc = fc->next) { fc->fcp_register = fcp_register; count++; } ret = fcp_initialize (fcchain, count); if (ret) return ret; if (!fc_channels) fc_channels = fcchain; else { for (fc = fc_channels; fc->next; fc = fc->next); fc->next = fcchain; } return ret;}void fcp_release(fc_channel *fcchain, int count) /* count must > 0 */{ fc_channel *fc; fc_channel *fcx; for (fc = fcchain; --count && fc->next; fc = fc->next); if (count) { printk("FC: nothing to release\n"); return; } if (fc_channels == fcchain) fc_channels = fc->next; else { for (fcx = fc_channels; fcx->next != fcchain; fcx = fcx->next); fcx->next = fc->next; } fc->next = NULL; /* * We've just grabbed fcchain out of the fc_channel list * and zero-terminated it, while destroying the count. * * Freeing the fc's is the low level driver's responsibility. */}static void fcp_scsi_done (Scsi_Cmnd *SCpnt){ if (FCP_CMND(SCpnt)->done) FCP_CMND(SCpnt)->done(SCpnt);}static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, int prepare){ long i; fcp_cmd *cmd; u32 fcp_cntl; if (prepare) { i = find_first_zero_bit (fc->scsi_bitmap, fc->scsi_bitmap_end);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -