📄 megaraid.c
字号:
target = 0; } } } else { if( islogical ) { /* this is the logical channel */ channel = cmd->device->channel; } else { /* physical channel */ channel = cmd->device->channel - NVIRT_CHAN; target = cmd->device->id; } } if(islogical) { /* have just LUN 0 for each target on virtual channels */ if (cmd->device->lun) { cmd->result = (DID_BAD_TARGET << 16); cmd->scsi_done(cmd); return NULL; } ldrv_num = mega_get_ldrv_num(adapter, cmd, channel); max_ldrv_num = (adapter->flag & BOARD_40LD) ? MAX_LOGICAL_DRIVES_40LD : MAX_LOGICAL_DRIVES_8LD; /* * max_ldrv_num increases by 0x80 if some logical drive was * deleted. */ if(adapter->read_ldidmap) max_ldrv_num += 0x80; if(ldrv_num > max_ldrv_num ) { cmd->result = (DID_BAD_TARGET << 16); cmd->scsi_done(cmd); return NULL; } } else { if( cmd->device->lun > 7) { /* * Do not support lun >7 for physically accessed * devices */ cmd->result = (DID_BAD_TARGET << 16); cmd->scsi_done(cmd); return NULL; } } /* * * Logical drive commands * */ if(islogical) { switch (cmd->cmnd[0]) { case TEST_UNIT_READY:#if MEGA_HAVE_CLUSTERING /* * Do we support clustering and is the support enabled * If no, return success always */ if( !adapter->has_cluster ) { cmd->result = (DID_OK << 16); cmd->scsi_done(cmd); return NULL; } if(!(scb = mega_allocate_scb(adapter, cmd))) { *busy = 1; return NULL; } scb->raw_mbox[0] = MEGA_CLUSTER_CMD; scb->raw_mbox[2] = MEGA_RESERVATION_STATUS; scb->raw_mbox[3] = ldrv_num; scb->dma_direction = PCI_DMA_NONE; return scb;#else cmd->result = (DID_OK << 16); cmd->scsi_done(cmd); return NULL;#endif case MODE_SENSE: { char *buf; struct scatterlist *sg; sg = scsi_sglist(cmd); buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; memset(buf, 0, cmd->cmnd[4]); kunmap_atomic(buf - sg->offset, KM_IRQ0); cmd->result = (DID_OK << 16); cmd->scsi_done(cmd); return NULL; } case READ_CAPACITY: case INQUIRY: if(!(adapter->flag & (1L << cmd->device->channel))) { printk(KERN_NOTICE "scsi%d: scanning scsi channel %d ", adapter->host->host_no, cmd->device->channel); printk("for logical drives.\n"); adapter->flag |= (1L << cmd->device->channel); } /* Allocate a SCB and initialize passthru */ if(!(scb = mega_allocate_scb(adapter, cmd))) { *busy = 1; return NULL; } pthru = scb->pthru; mbox = (mbox_t *)scb->raw_mbox; memset(mbox, 0, sizeof(scb->raw_mbox)); memset(pthru, 0, sizeof(mega_passthru)); pthru->timeout = 0; pthru->ars = 1; pthru->reqsenselen = 14; pthru->islogical = 1; pthru->logdrv = ldrv_num; pthru->cdblen = cmd->cmd_len; memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len); if( adapter->has_64bit_addr ) { mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; } else { mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; } scb->dma_direction = PCI_DMA_FROMDEVICE; pthru->numsgelements = mega_build_sglist(adapter, scb, &pthru->dataxferaddr, &pthru->dataxferlen); mbox->m_out.xferaddr = scb->pthru_dma_addr; return scb; case READ_6: case WRITE_6: case READ_10: case WRITE_10: case READ_12: case WRITE_12: /* Allocate a SCB and initialize mailbox */ if(!(scb = mega_allocate_scb(adapter, cmd))) { *busy = 1; return NULL; } mbox = (mbox_t *)scb->raw_mbox; memset(mbox, 0, sizeof(scb->raw_mbox)); mbox->m_out.logdrv = ldrv_num; /* * A little hack: 2nd bit is zero for all scsi read * commands and is set for all scsi write commands */ if( adapter->has_64bit_addr ) { mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? MEGA_MBOXCMD_LWRITE64: MEGA_MBOXCMD_LREAD64 ; } else { mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? MEGA_MBOXCMD_LWRITE: MEGA_MBOXCMD_LREAD ; } /* * 6-byte READ(0x08) or WRITE(0x0A) cdb */ if( cmd->cmd_len == 6 ) { mbox->m_out.numsectors = (u32) cmd->cmnd[4]; mbox->m_out.lba = ((u32)cmd->cmnd[1] << 16) | ((u32)cmd->cmnd[2] << 8) | (u32)cmd->cmnd[3]; mbox->m_out.lba &= 0x1FFFFF;#if MEGA_HAVE_STATS /* * Take modulo 0x80, since the logical drive * number increases by 0x80 when a logical * drive was deleted */ if (*cmd->cmnd == READ_6) { adapter->nreads[ldrv_num%0x80]++; adapter->nreadblocks[ldrv_num%0x80] += mbox->m_out.numsectors; } else { adapter->nwrites[ldrv_num%0x80]++; adapter->nwriteblocks[ldrv_num%0x80] += mbox->m_out.numsectors; }#endif } /* * 10-byte READ(0x28) or WRITE(0x2A) cdb */ if( cmd->cmd_len == 10 ) { mbox->m_out.numsectors = (u32)cmd->cmnd[8] | ((u32)cmd->cmnd[7] << 8); mbox->m_out.lba = ((u32)cmd->cmnd[2] << 24) | ((u32)cmd->cmnd[3] << 16) | ((u32)cmd->cmnd[4] << 8) | (u32)cmd->cmnd[5];#if MEGA_HAVE_STATS if (*cmd->cmnd == READ_10) { adapter->nreads[ldrv_num%0x80]++; adapter->nreadblocks[ldrv_num%0x80] += mbox->m_out.numsectors; } else { adapter->nwrites[ldrv_num%0x80]++; adapter->nwriteblocks[ldrv_num%0x80] += mbox->m_out.numsectors; }#endif } /* * 12-byte READ(0xA8) or WRITE(0xAA) cdb */ if( cmd->cmd_len == 12 ) { mbox->m_out.lba = ((u32)cmd->cmnd[2] << 24) | ((u32)cmd->cmnd[3] << 16) | ((u32)cmd->cmnd[4] << 8) | (u32)cmd->cmnd[5]; mbox->m_out.numsectors = ((u32)cmd->cmnd[6] << 24) | ((u32)cmd->cmnd[7] << 16) | ((u32)cmd->cmnd[8] << 8) | (u32)cmd->cmnd[9];#if MEGA_HAVE_STATS if (*cmd->cmnd == READ_12) { adapter->nreads[ldrv_num%0x80]++; adapter->nreadblocks[ldrv_num%0x80] += mbox->m_out.numsectors; } else { adapter->nwrites[ldrv_num%0x80]++; adapter->nwriteblocks[ldrv_num%0x80] += mbox->m_out.numsectors; }#endif } /* * If it is a read command */ if( (*cmd->cmnd & 0x0F) == 0x08 ) { scb->dma_direction = PCI_DMA_FROMDEVICE; } else { scb->dma_direction = PCI_DMA_TODEVICE; } /* Calculate Scatter-Gather info */ mbox->m_out.numsgelements = mega_build_sglist(adapter, scb, (u32 *)&mbox->m_out.xferaddr, (u32 *)&seg); return scb;#if MEGA_HAVE_CLUSTERING case RESERVE: /* Fall through */ case RELEASE: /* * Do we support clustering and is the support enabled */ if( ! adapter->has_cluster ) { cmd->result = (DID_BAD_TARGET << 16); cmd->scsi_done(cmd); return NULL; } /* Allocate a SCB and initialize mailbox */ if(!(scb = mega_allocate_scb(adapter, cmd))) { *busy = 1; return NULL; } scb->raw_mbox[0] = MEGA_CLUSTER_CMD; scb->raw_mbox[2] = ( *cmd->cmnd == RESERVE ) ? MEGA_RESERVE_LD : MEGA_RELEASE_LD; scb->raw_mbox[3] = ldrv_num; scb->dma_direction = PCI_DMA_NONE; return scb;#endif default: cmd->result = (DID_BAD_TARGET << 16); cmd->scsi_done(cmd); return NULL; } } /* * Passthru drive commands */ else { /* Allocate a SCB and initialize passthru */ if(!(scb = mega_allocate_scb(adapter, cmd))) { *busy = 1; return NULL; } mbox = (mbox_t *)scb->raw_mbox; memset(mbox, 0, sizeof(scb->raw_mbox)); if( adapter->support_ext_cdb ) { epthru = mega_prepare_extpassthru(adapter, scb, cmd, channel, target); mbox->m_out.cmd = MEGA_MBOXCMD_EXTPTHRU; mbox->m_out.xferaddr = scb->epthru_dma_addr; } else { pthru = mega_prepare_passthru(adapter, scb, cmd, channel, target); /* Initialize mailbox */ if( adapter->has_64bit_addr ) { mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; } else { mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; } mbox->m_out.xferaddr = scb->pthru_dma_addr; } return scb; } return NULL;}/** * mega_prepare_passthru() * @adapter - pointer to our soft state * @scb - our scsi control block * @cmd - scsi command from the mid-layer * @channel - actual channel on the controller * @target - actual id on the controller. * * prepare a command for the scsi physical devices. */static mega_passthru *mega_prepare_passthru(adapter_t *adapter, scb_t *scb, Scsi_Cmnd *cmd, int channel, int target){ mega_passthru *pthru; pthru = scb->pthru; memset(pthru, 0, sizeof (mega_passthru)); /* 0=6sec/1=60sec/2=10min/3=3hrs */ pthru->timeout = 2; pthru->ars = 1; pthru->reqsenselen = 14; pthru->islogical = 0; pthru->channel = (adapter->flag & BOARD_40LD) ? 0 : channel; pthru->target = (adapter->flag & BOARD_40LD) ? (channel << 4) | target : target; pthru->cdblen = cmd->cmd_len; pthru->logdrv = cmd->device->lun; memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len); /* Not sure about the direction */ scb->dma_direction = PCI_DMA_BIDIRECTIONAL; /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */ switch (cmd->cmnd[0]) { case INQUIRY: case READ_CAPACITY: if(!(adapter->flag & (1L << cmd->device->channel))) { printk(KERN_NOTICE "scsi%d: scanning scsi channel %d [P%d] ", adapter->host->host_no, cmd->device->channel, channel); printk("for physical devices.\n"); adapter->flag |= (1L << cmd->device->channel); } /* Fall through */ default: pthru->numsgelements = mega_build_sglist(adapter, scb, &pthru->dataxferaddr, &pthru->dataxferlen); break; } return pthru;}/** * mega_prepare_extpassthru() * @adapter - pointer to our soft state * @scb - our scsi control block * @cmd - scsi command from the mid-layer * @channel - actual channel on the controller * @target - actual id on the controller. * * prepare a command for the scsi physical devices. This rountine prepares * commands for devices which can take extended CDBs (>10 bytes) */static mega_ext_passthru *mega_prepare_extpassthru(adapter_t *adapter, scb_t *scb, Scsi_Cmnd *cmd, int channel, int target){ mega_ext_passthru *epthru; epthru = scb->epthru; memset(epthru, 0, sizeof(mega_ext_passthru)); /* 0=6sec/1=60sec/2=10min/3=3hrs */ epthru->timeout = 2; epthru->ars = 1; epthru->reqsenselen = 14; epthru->islogical = 0; epthru->channel = (adapter->flag & BOARD_40LD) ? 0 : channel; epthru->target = (adapter->flag & BOARD_40LD) ? (channel << 4) | target : target; epthru->cdblen = cmd->cmd_len; epthru->logdrv = cmd->device->lun; memcpy(epthru->cdb, cmd->cmnd, cmd->cmd_len); /* Not sure about the direction */ scb->dma_direction = PCI_DMA_BIDIRECTIONAL; switch(cmd->cmnd[0]) { case INQUIRY: case READ_CAPACITY: if(!(adapter->flag & (1L << cmd->device->channel))) { printk(KERN_NOTICE "scsi%d: scanning scsi channel %d [P%d] ", adapter->host->host_no, cmd->device->channel, channel); printk("for physical devices.\n"); adapter->flag |= (1L << cmd->device->channel); } /* Fall through */ default: epthru->numsgelements = mega_build_sglist(adapter, scb, &epthru->dataxferaddr, &epthru->dataxferlen); break; } return epthru;}static void__mega_runpendq(adapter_t *adapter){ scb_t *scb; struct list_head *pos, *next; /* Issue any pending commands to the card */ list_for_each_safe(pos, next, &adapter->pending_list) { scb = list_entry(pos, scb_t, list); if( !(scb->state & SCB_ISSUED) ) { if( issue_scb(adapter, scb) != 0 ) return; } } return;}/** * issue_scb() * @adapter - pointer to our soft state * @scb - scsi control block * * Post a command to the card if the mailbox is available, otherwise return * busy. We also take the scb from the pending list if the mailbox is * available. */static intissue_scb(adapter_t *adapter, scb_t *scb){ volatile mbox64_t *mbox64 = adapter->mbox64; volatile mbox_t *mbox = adapter->mbox; unsigned int i = 0; if(unlikely(mbox->m_in.busy)) { do { udelay(1); i++; } while( mbox->m_in.busy && (i < max_mbox_busy_wait) ); if(mbox->m_in.busy) return -1; } /* Copy mailbox data into host structure */ memcpy((char *)&mbox->m_out, (char *)scb->raw_mbox, sizeof(struct mbox_out)); mbox->m_out.cmdid = scb->idx; /* Set cmdid */ mbox->m_in.busy = 1; /* Set busy */ /* * Increment the pending queue counter */ atomic_inc(&adapter->pend_cmds);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -