📄 dpt_i2o.c
字号:
adpt_hba* pHba=NULL; u32 m; ulong reply; u32 status=0; u32 context; ulong flags = 0; pHba = dev_id; if (pHba == NULL ){ printk(KERN_WARNING"adpt_isr: NULL dev_id\n"); return; } spin_lock_irqsave(&io_request_lock, flags); while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) { m = readl(pHba->reply_port); if(m == EMPTY_QUEUE){ // Try twice then give up rmb(); m = readl(pHba->reply_port); if(m == EMPTY_QUEUE){ // This really should not happen printk(KERN_ERR"dpti: Could not get reply frame\n"); spin_unlock_irqrestore(&io_request_lock,flags); return; } } reply = (ulong)bus_to_virt(m); if (readl(reply) & MSG_FAIL) { u32 old_m = readl(reply+28); ulong msg; u32 old_context; PDEBUG("%s: Failed message\n",pHba->name); if(old_m >= 0x100000){ printk(KERN_ERR"%s: Bad preserved MFA (%x)- dropping frame\n",pHba->name,old_m); writel(m,pHba->reply_port); continue; } // Transaction context is 0 in failed reply frame msg = (ulong)(pHba->msg_addr_virt + old_m); old_context = readl(msg+12); writel(old_context, reply+12); adpt_send_nop(pHba, old_m); } context = readl(reply+8); if(context & 0x40000000){ // IOCTL ulong p = (ulong)(readl(reply+12)); if( p != 0) { memcpy((void*)p, (void*)reply, REPLY_FRAME_SIZE * 4); } // All IOCTLs will also be post wait } if(context & 0x80000000){ // Post wait message status = readl(reply+16); if(status >> 24){ status &= 0xffff; /* Get detail status */ } else { status = I2O_POST_WAIT_OK; } if(!(context & 0x40000000)) { cmd = (Scsi_Cmnd*) readl(reply+12); if(cmd != NULL) { printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context); } } adpt_i2o_post_wait_complete(context, status); } else { // SCSI message cmd = (Scsi_Cmnd*) readl(reply+12); if(cmd != NULL){ if(cmd->serial_number != 0) { // If not timedout adpt_i2o_to_scsi(reply, cmd); } } } writel(m, pHba->reply_port); wmb(); rmb(); } spin_unlock_irqrestore(&io_request_lock, flags); return;}static s32 adpt_scsi_to_i2o(adpt_hba* pHba, Scsi_Cmnd* cmd, struct adpt_device* d){ int i; u32 msg[MAX_MESSAGE_SIZE]; u32* mptr; u32 *lenptr; int direction; int scsidir; u32 len; u32 reqlen; s32 rcode; memset(msg, 0 , sizeof(msg)); len = cmd->request_bufflen; direction = 0x00000000; scsidir = 0x00000000; // DATA NO XFER if(len) { /* * Set SCBFlags to indicate if data is being transferred * in or out, or no data transfer * Note: Do not have to verify index is less than 0 since * cmd->cmnd[0] is an unsigned char */ switch(cmd->sc_data_direction){ case SCSI_DATA_READ: scsidir =0x40000000; // DATA IN (iop<--dev) break; case SCSI_DATA_WRITE: direction=0x04000000; // SGL OUT scsidir =0x80000000; // DATA OUT (iop-->dev) break; case SCSI_DATA_NONE: break; case SCSI_DATA_UNKNOWN: scsidir =0x40000000; // DATA IN (iop<--dev) // Assume In - and continue; break; default: printk(KERN_WARNING"%s: scsi opcode 0x%x not supported.\n", pHba->name, cmd->cmnd[0]); cmd->result = (DID_OK <<16) | (INITIATOR_ERROR << 8); cmd->scsi_done(cmd); return 0; } } // msg[0] is set later // I2O_CMD_SCSI_EXEC msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid); msg[2] = 0; msg[3] = (u32)cmd; /* We want the SCSI control block back */ // Our cards use the transaction context as the tag for queueing // Adaptec/DPT Private stuff msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16); msg[5] = d->tid; /* Direction, disconnect ok | sense data | simple queue , CDBLen */ // I2O_SCB_FLAG_ENABLE_DISCONNECT | // I2O_SCB_FLAG_SIMPLE_QUEUE_TAG | // I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE; msg[6] = scsidir|0x20a00000|cmd->cmd_len; mptr=msg+7; // Write SCSI command into the message - always 16 byte block memset(mptr, 0, 16); memcpy(mptr, cmd->cmnd, cmd->cmd_len); mptr+=4; lenptr=mptr++; /* Remember me - fill in when we know */ reqlen = 14; // SINGLE SGE /* Now fill in the SGList and command */ if(cmd->use_sg) { struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer; len = 0; for(i = 0 ; i < cmd->use_sg; i++) { *mptr++ = direction|0x10000000|sg->length; len+=sg->length; *mptr++ = virt_to_bus(sg->address); sg++; } /* Make this an end of list */ mptr[-2] = direction|0xD0000000|(sg-1)->length; reqlen = mptr - msg; *lenptr = len; if(cmd->underflow && len != cmd->underflow){ printk(KERN_WARNING"Cmd len %08X Cmd underflow %08X\n", len, cmd->underflow); } } else { *lenptr = len = cmd->request_bufflen; if(len == 0) { reqlen = 12; } else { *mptr++ = 0xD0000000|direction|cmd->request_bufflen; *mptr++ = virt_to_bus(cmd->request_buffer); } } /* Stick the headers on */ msg[0] = reqlen<<16 | ((reqlen > 12) ? SGL_OFFSET_12 : SGL_OFFSET_0); // Send it on it's way rcode = adpt_i2o_post_this(pHba, msg, reqlen<<2); if (rcode == 0) { return 0; } return rcode;}static s32 adpt_scsi_register(adpt_hba* pHba,Scsi_Host_Template * sht){ struct Scsi_Host *host = NULL; host = scsi_register(sht, sizeof(adpt_hba*)); if (host == NULL) { printk ("%s: scsi_register returned NULL\n",pHba->name); return -1; } (adpt_hba*)(host->hostdata[0]) = pHba; pHba->host = host; host->irq = pHba->pDev->irq;; /* no IO ports, so don't have to set host->io_port and * host->n_io_port */ host->io_port = 0; host->n_io_port = 0; /* see comments in hosts.h */ host->max_id = 16; host->max_lun = 256; host->max_channel = pHba->top_scsi_channel + 1; host->cmd_per_lun = 256; host->unique_id = (uint) pHba; host->sg_tablesize = pHba->sg_tablesize; host->can_queue = pHba->post_fifo_size; host->select_queue_depths = adpt_select_queue_depths; return 0;}static s32 adpt_i2o_to_scsi(ulong reply, Scsi_Cmnd* cmd){ adpt_hba* pHba; u32 hba_status; u32 dev_status; u32 reply_flags = readl(reply) & 0xff00; // Leave it shifted up 8 bits // I know this would look cleaner if I just read bytes // but the model I have been using for all the rest of the // io is in 4 byte words - so I keep that model u16 detailed_status = readl(reply+16) &0xffff; dev_status = (detailed_status & 0xff); hba_status = detailed_status >> 8; // calculate resid for sg cmd->resid = cmd->request_bufflen - readl(reply+5); pHba = (adpt_hba*) cmd->host->hostdata[0]; cmd->sense_buffer[0] = '\0'; // initialize sense valid flag to false if(!(reply_flags & MSG_FAIL)) { switch(detailed_status & I2O_SCSI_DSC_MASK) { case I2O_SCSI_DSC_SUCCESS: cmd->result = (DID_OK << 16); // handle underflow if(readl(reply+5) < cmd->underflow ) { cmd->result = (DID_ERROR <<16); printk(KERN_WARNING"%s: SCSI CMD underflow\n",pHba->name); } break; case I2O_SCSI_DSC_REQUEST_ABORTED: cmd->result = (DID_ABORT << 16); break; case I2O_SCSI_DSC_PATH_INVALID: case I2O_SCSI_DSC_DEVICE_NOT_PRESENT: case I2O_SCSI_DSC_SELECTION_TIMEOUT: case I2O_SCSI_DSC_COMMAND_TIMEOUT: case I2O_SCSI_DSC_NO_ADAPTER: case I2O_SCSI_DSC_RESOURCE_UNAVAILABLE: printk(KERN_WARNING"%s: SCSI Timeout-Device (%d,%d,%d) hba status=0x%x, dev status=0x%x, cmd=0x%x\n", pHba->name, (u32)cmd->channel, (u32)cmd->target, (u32)cmd->lun, hba_status, dev_status, cmd->cmnd[0]); cmd->result = (DID_TIME_OUT << 16); break; case I2O_SCSI_DSC_ADAPTER_BUSY: case I2O_SCSI_DSC_BUS_BUSY: cmd->result = (DID_BUS_BUSY << 16); break; case I2O_SCSI_DSC_SCSI_BUS_RESET: case I2O_SCSI_DSC_BDR_MESSAGE_SENT: cmd->result = (DID_RESET << 16); break; case I2O_SCSI_DSC_PARITY_ERROR_FAILURE: printk(KERN_WARNING"%s: SCSI CMD parity error\n",pHba->name); cmd->result = (DID_PARITY << 16); break; case I2O_SCSI_DSC_UNABLE_TO_ABORT: case I2O_SCSI_DSC_COMPLETE_WITH_ERROR: case I2O_SCSI_DSC_UNABLE_TO_TERMINATE: case I2O_SCSI_DSC_MR_MESSAGE_RECEIVED: case I2O_SCSI_DSC_AUTOSENSE_FAILED: case I2O_SCSI_DSC_DATA_OVERRUN: case I2O_SCSI_DSC_UNEXPECTED_BUS_FREE: case I2O_SCSI_DSC_SEQUENCE_FAILURE: case I2O_SCSI_DSC_REQUEST_LENGTH_ERROR: case I2O_SCSI_DSC_PROVIDE_FAILURE: case I2O_SCSI_DSC_REQUEST_TERMINATED: case I2O_SCSI_DSC_IDE_MESSAGE_SENT: case I2O_SCSI_DSC_UNACKNOWLEDGED_EVENT: case I2O_SCSI_DSC_MESSAGE_RECEIVED: case I2O_SCSI_DSC_INVALID_CDB: case I2O_SCSI_DSC_LUN_INVALID: case I2O_SCSI_DSC_SCSI_TID_INVALID: case I2O_SCSI_DSC_FUNCTION_UNAVAILABLE: case I2O_SCSI_DSC_NO_NEXUS: case I2O_SCSI_DSC_CDB_RECEIVED: case I2O_SCSI_DSC_LUN_ALREADY_ENABLED: case I2O_SCSI_DSC_QUEUE_FROZEN: case I2O_SCSI_DSC_REQUEST_INVALID: default: printk(KERN_WARNING"%s: SCSI error %0x-Device(%d,%d,%d) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n", pHba->name, detailed_status & I2O_SCSI_DSC_MASK, (u32)cmd->channel, (u32)cmd->target, (u32)cmd-> lun, hba_status, dev_status, cmd->cmnd[0]); cmd->result = (DID_ERROR << 16); break; } // copy over the request sense data if it was a check // condition status if(dev_status == 0x02 /*CHECK_CONDITION*/) { u32 len = sizeof(cmd->sense_buffer); len = (len > 40) ? 40 : len; // Copy over the sense data memcpy(cmd->sense_buffer, (void*)(reply+28) , len); if(cmd->sense_buffer[0] == 0x70 /* class 7 */ && cmd->sense_buffer[2] == DATA_PROTECT ){ /* This is to handle an array failed */ cmd->result = (DID_TIME_OUT << 16); printk(KERN_WARNING"%s: SCSI Data Protect-Device (%d,%d,%d) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n", pHba->name, (u32)cmd->channel, (u32)cmd->target, (u32)cmd->lun, hba_status, dev_status, cmd->cmnd[0]); } } } else { /* In this condtion we could not talk to the tid * the card rejected it. We should signal a retry * for a limitted number of retries. */ cmd->result = (DID_TIME_OUT << 16); printk(KERN_WARNING"%s: I2O MSG_FAIL - Device (%d,%d,%d) tid=%d, cmd=0x%x\n", pHba->name, (u32)cmd->channel, (u32)cmd->target, (u32)cmd-> lun, ((struct adpt_device*)(cmd->device->hostdata))->tid, cmd->cmnd[0]); } cmd->result |= (dev_status); if(cmd->scsi_done != NULL){ cmd->scsi_done(cmd); } return cmd->result;}static s32 adpt_rescan(adpt_hba* pHba){ s32 rcode; ulong flags; spin_lock_irqsave(&io_request_lock, flags); if ((rcode=adpt_i2o_lct_get(pHba)) < 0){ spin_unlock_irqrestore(&io_request_lock, flags); return rcode; } if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0){ spin_unlock_irqrestore(&io_request_lock, flags); return rcode; } spin_unlock_irqrestore(&io_request_lock, flags); return 0;}static s32 adpt_i2o_reparse_lct(adpt_hba* pHba){ int i; int max; int tid; struct i2o_device *d; i2o_lct *lct = pHba->lct; u8 bus_no = 0; s16 scsi_id; s16 scsi_lun; u32 buf[10]; // at least 8 u32's struct adpt_device* pDev = NULL; struct i2o_device* pI2o_dev = NULL; if (lct == NULL) { printk(KERN_ERR "%s: LCT is empty???\n",pHba->name); return -1; } max = lct->table_size; max -= 3; max /= 9; // Mark each drive as unscanned for (d = pHba->devices; d; d = d->next) { pDev =(struct adpt_device*) d->owner; if(!pDev){ continue; } pDev->state |= DPTI_DEV_UNSCANNED; } printk(KERN_INFO "%s: LCT has %d entries.\n", pHba->name,max); for(i=0;i<max;i++) { if( lct->lct_entry[i].user_tid != 0xfff){ continue; } if( lct->lct_entry[i].class_id == I2O_CLASS_RANDOM_BLOCK_STORAGE || lct->lct_entry[i].class_id == I2O_CLASS_SCSI_PERIPHERAL || lct->lct_entry[i].class_id == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){ tid = lct->lct_entry[i].tid; if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) { printk(KERN_ERR"%s: Could not query device\n",pHba->name); continue; } bus_no = buf[0]>>16; scsi_id = buf[1]; scsi_lun = (buf[2]>>8 )&0xff; pDev = pHba->channel[bus_no].device[scsi_id]; /* da lun */ while(pDev) { if(pDev->scsi_lun == scsi_lun) { break; } pDev = pDev->next_lun; } if(!pDev ) { // Something new add it d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL); if(d==NULL) { printk(KERN_CRIT "Out of memory for I2O device data.\n"); return -ENOMEM; } d->controller = (void*)pHba; d->next = NULL; memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); d->flags = 0; adpt_i2o_report_hba_unit(pHba, d); adpt_i2o_install_device(pHba, d); if(bus_no >= MAX_CHANNEL) { // Something wrong skip it printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no); continue; } pDev = pHba->channel[bus_no].device[scsi_id]; if( pDev == NULL){ pDev = kmalloc(sizeof(struct adpt_device),GFP_KERNEL); if(pDev == NULL) { return -ENOMEM; } pHba->channel[bus_no].device[scsi_id] = pDev; } else { while (pDev->next_lun) { pDev = pDev->next_lun; } pDev = pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL); if(pDev == NULL) { return -ENOMEM; } } memset(pDev,0,sizeof(struct adpt_device)); pDev->tid = d->lct_data.tid; pDev->scsi_channel = bus_no; pDev->scsi_id = scsi_id; pDev->scsi_lun = scsi_lun; pDev->pI2o_dev = d; d->owner = pDev; pDev->type = (buf[0])&0xff; pDev->flags = (buf[0]>>8)&0xff; // Too late, SCSI system has made up it's mind, but what the hey ... if(scsi_id > pHba->top_scsi_id){ pHba->top_scsi_id = scsi_id; } if(scsi_lun > pHba->top_scsi_lun){ pHba->top_scsi_lun = scsi_lun; } continue; } // end of new i2o device // We found an old device - check it while(pDev) { if(pDev->scsi_lun == scsi_lun) { if(pDev->pScsi_dev->online == FALSE) { printk(KERN_WARNING"%s: Setting device (%d,%d,%d) back online\n", pHba->name,bus_no,scsi_id,scsi_lun); if (pDev->pScsi_dev) { pDev->pScsi_dev->online = TRUE; } } d = pDev->pI2o_dev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -