📄 megaraid.c
字号:
megaCfg->nWriteBlocks[(int) lun] += mbox->numsectors; } }#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10 || *SCpnt->cmnd == READ_12) { pScb->dma_direction = PCI_DMA_FROMDEVICE; } else { /*WRITE_6 or WRITE_10 */ pScb->dma_direction = PCI_DMA_TODEVICE; }#endif /* Calculate Scatter-Gather info */ mbox->numsgelements = mega_build_sglist (megaCfg, pScb, (u32 *)&mbox->xferaddr, (u32 *)&seg);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pScb->iDataSize = seg; if (mbox->numsgelements) { pScb->dma_type = M_RD_SGLIST_ONLY; TRACE1 (("M_RD_SGLIST_ONLY Enabled \n")); } else { pScb->dma_type = M_RD_BULK_DATA_ONLY; TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n")); }#endif return pScb; default: SCpnt->result = (DID_BAD_TARGET << 16); callDone (SCpnt); return NULL; } } /*----------------------------------------------------- * * Passthru drive commands * *-----------------------------------------------------*/ else { /* Allocate a SCB and initialize passthru */ if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); callDone (SCpnt); return NULL; } mbox = (mega_mailbox *) pScb->mboxData; memset (mbox, 0, sizeof (pScb->mboxData)); if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) { epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt); mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) mbox->xferaddr = pScb->dma_ext_passthruhandle64; if(epthru->numsgelements) { pScb->dma_type = M_RD_PTHRU_WITH_SGLIST; } else { pScb->dma_type = M_RD_EPTHRU_WITH_BULK_DATA; }#else mbox->xferaddr = virt_to_bus(epthru);#endif } else { pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt); /* Initialize mailbox */ mbox->cmd = MEGA_MBOXCMD_PASSTHRU;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) mbox->xferaddr = pScb->dma_passthruhandle64; if (pthru->numsgelements) { pScb->dma_type = M_RD_PTHRU_WITH_SGLIST; } else { pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA; }#else mbox->xferaddr = virt_to_bus(pthru);#endif } return pScb; } return NULL;}static intmega_get_lun(mega_host_config *this_hba, Scsi_Cmnd *sc){ int tgt; int lun; int virt_chan; tgt = sc->target; if ( tgt > 7 ) tgt--; /* we do not get inquires for tgt 7 */ virt_chan = sc->channel - this_hba->productInfo.SCSIChanPresent; lun = (virt_chan * 15) + tgt; /* * If "delete logical drive" feature is enabled on this controller. * Do only if at least one delete logical drive operation was done. * * Also, after logical drive deletion, instead of logical drive number, * the value returned should be 0x80+logical drive id. * * These is valid only for IO commands. */ if( this_hba->support_random_del && this_hba->read_ldidmap ) { switch(sc->cmnd[0]) { case READ_6: /* fall through */ case WRITE_6: /* fall through */ case READ_10: /* fall through */ case WRITE_10: lun += 0x80; } } return lun;}static mega_passthru *mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc){ mega_passthru *pthru;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pthru = scb->pthru;#else pthru = &scb->pthru;#endif memset (pthru, 0, sizeof (mega_passthru)); /* set adapter timeout value to 10 min. for tape drive */ /* 0=6sec/1=60sec/2=10min/3=3hrs */ pthru->timeout = 2; pthru->ars = 1; pthru->reqsenselen = 14; pthru->islogical = 0; pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel; pthru->target = (megacfg->flag & BOARD_40LD) ? (sc->channel << 4) | sc->target : sc->target; pthru->cdblen = sc->cmd_len; pthru->logdrv = sc->lun; memcpy (pthru->cdb, sc->cmnd, sc->cmd_len);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* Not sure about the direction */ scb->dma_direction = PCI_DMA_BIDIRECTIONAL; /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */ switch (sc->cmnd[0]) { case INQUIRY: case READ_CAPACITY: pthru->numsgelements = 0; pthru->dataxferaddr = scb->dma_bounce_buffer; pthru->dataxferlen = sc->request_bufflen; break; default: pthru->numsgelements = mega_build_sglist( megacfg, scb, (u32 *)&pthru->dataxferaddr, (u32 *)&pthru->dataxferlen ); break; }#else pthru->numsgelements = mega_build_sglist( megacfg, scb, (u32 *)&pthru->dataxferaddr, (u32 *)&pthru->dataxferlen );#endif return pthru;}static mega_ext_passthru *mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc){ mega_ext_passthru *epthru;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) epthru = scb->epthru;#else epthru = &scb->epthru;#endif memset(epthru, 0, sizeof(mega_ext_passthru)); /* set adapter timeout value to 10 min. for tape drive */ /* 0=6sec/1=60sec/2=10min/3=3hrs */ epthru->timeout = 2; epthru->ars = 1; epthru->reqsenselen = 14; epthru->islogical = 0; epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel; epthru->target = (megacfg->flag & BOARD_40LD) ? (sc->channel << 4) | sc->target : sc->target; epthru->cdblen = sc->cmd_len; epthru->logdrv = sc->lun; memcpy(epthru->cdb, sc->cmnd, sc->cmd_len);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* Not sure about the direction */ scb->dma_direction = PCI_DMA_BIDIRECTIONAL; /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */ switch (sc->cmnd[0]) { case INQUIRY: case READ_CAPACITY: epthru->numsgelements = 0; epthru->dataxferaddr = scb->dma_bounce_buffer; epthru->dataxferlen = sc->request_bufflen; break; default: epthru->numsgelements = mega_build_sglist( megacfg, scb, (u32 *)&epthru->dataxferaddr, (u32 *)&epthru->dataxferlen ); break; }#else epthru->numsgelements = mega_build_sglist( megacfg, scb, (u32 *)&epthru->dataxferaddr, (u32 *)&epthru->dataxferlen );#endif return epthru;}/* Handle Driver Level IOCTLs * Return value of 0 indicates this function could not handle , so continue * processing*/static int mega_driver_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt){ unsigned char *data = (unsigned char *) SCpnt->request_buffer; mega_driver_info driver_info; /* If this is not our command dont do anything */ if (SCpnt->cmnd[0] != M_RD_DRIVER_IOCTL_INTERFACE) return 0; switch (SCpnt->cmnd[1]) { case GET_DRIVER_INFO: if (SCpnt->request_bufflen < sizeof (driver_info)) { SCpnt->result = DID_BAD_TARGET << 16; callDone (SCpnt); return 1; } driver_info.size = sizeof (driver_info) - sizeof (int); driver_info.version = MEGARAID_IOCTL_VERSION; memcpy (data, &driver_info, sizeof (driver_info)); break; default: SCpnt->result = DID_BAD_TARGET << 16; } callDone (SCpnt); return 1;}static void inline set_mbox_xfer_addr (mega_host_config * megaCfg, mega_scb * pScb, mega_ioctl_mbox * mbox, u32 direction){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) switch (direction) { case TO_DEVICE: pScb->dma_direction = PCI_DMA_TODEVICE; break; case FROM_DEVICE: pScb->dma_direction = PCI_DMA_FROMDEVICE; break; case FROMTO_DEVICE: pScb->dma_direction = PCI_DMA_BIDIRECTIONAL; break; } pScb->dma_h_bulkdata = pci_map_single (megaCfg->dev, pScb->buff_ptr, pScb->iDataSize, pScb->dma_direction); mbox->xferaddr = pScb->dma_h_bulkdata; pScb->dma_type = M_RD_BULK_DATA_ONLY; TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n"));#else mbox->xferaddr = virt_to_bus (pScb->buff_ptr);#endif}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)/*-------------------------------------------------------------------- * build RAID commands for controller, passed down through ioctl() *--------------------------------------------------------------------*/static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt){ mega_scb *pScb; mega_ioctl_mbox *mbox; mega_mailbox *mailbox; mega_passthru *pthru; u8 *mboxdata; long seg, i = 0; unsigned char *data = (unsigned char *) SCpnt->request_buffer; if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); callDone (SCpnt); return NULL; } pthru = &pScb->pthru; mboxdata = (u8 *) & pScb->mboxData; mbox = (mega_ioctl_mbox *) & pScb->mboxData; mailbox = (mega_mailbox *) & pScb->mboxData; memset (mailbox, 0, sizeof (pScb->mboxData)); if (data[0] == 0x03) { /* passthrough command */ unsigned char cdblen = data[2]; memset (pthru, 0, sizeof (mega_passthru)); pthru->islogical = (data[cdblen + 3] & 0x80) ? 1 : 0; pthru->timeout = data[cdblen + 3] & 0x07; pthru->reqsenselen = 14; pthru->ars = (data[cdblen + 3] & 0x08) ? 1 : 0; pthru->logdrv = data[cdblen + 4]; pthru->channel = data[cdblen + 5]; pthru->target = data[cdblen + 6]; pthru->cdblen = cdblen; memcpy (pthru->cdb, &data[3], cdblen); mailbox->cmd = MEGA_MBOXCMD_PASSTHRU; pthru->numsgelements = mega_build_sglist (megaCfg, pScb, (u32 *) & pthru-> dataxferaddr, (u32 *) & pthru-> dataxferlen); mailbox->xferaddr = virt_to_bus (pthru); for (i = 0; i < (SCpnt->request_bufflen - cdblen - 7); i++) { data[i] = data[i + cdblen + 7]; } return pScb; } /* else normal (nonpassthru) command */#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24) /*0x020024 */ /* *usage of the function copy from user is used in case of data more than *4KB.This is used only with adapters which supports more than 8 logical * drives.This feature is disabled on kernels earlier or same as 2.0.36 * as the uaccess.h file is not available with those kernels. */ if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { /* use external data area for large xfers */ /* If cmnd[0] is set to M_RD_IOCTL_CMD_NEW then * * cmnd[4..7] = external user buffer * * cmnd[8..11] = length of buffer * * */ char *user_area = (char *)*((u32*)&SCpnt->cmnd[4]); u32 xfer_size = *((u32 *) & SCpnt->cmnd[8]); switch (data[0]) { case FW_FIRE_WRITE: case FW_FIRE_FLASH: if ((ulong) user_area & (PAGE_SIZE - 1)) { printk ("megaraid:user address not aligned on 4K boundary.Error.\n"); SCpnt->result = (DID_ERROR << 16); callDone (SCpnt); return NULL; } break; default: break; } if (!(pScb->buff_ptr = kmalloc (xfer_size, GFP_KERNEL))) { printk ("megaraid: Insufficient mem for M_RD_IOCTL_CMD_NEW.\n"); SCpnt->result = (DID_ERROR << 16); callDone (SCpnt); return NULL; } copy_from_user (pScb->buff_ptr, user_area, xfer_size); pScb->iDataSize = xfer_size; switch (data[0]) { case DCMD_FC_CMD: switch (data[1]) { case DCMD_FC_READ_NVRAM_CONFIG: case DCMD_GET_DISK_CONFIG: { if ((ulong) pScb-> buff_ptr & (PAGE_SIZE - 1)) { printk ("megaraid:user address not sufficient Error.\n"); SCpnt->result = (DID_ERROR << 16); callDone (SCpnt); return NULL; } /*building SG list */ mega_build_kernel_sg (pScb->buff_ptr, xfer_size, pScb, mbox); break; } default: break; } /*switch (data[1]) */ break; } }#endif mbox->cmd = data[0]; mbox->channel = data[1]; mbox->param = data[2]; mbox->pad[0] = data[3]; mbox->logdrv = data[4]; if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { switch (data[0]) { case FW_FIRE_WRITE: mbox->cmd = FW_FIRE_WRITE; mbox->channel = data[1]; /* Current Block Number */ set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE); mbox->numsgelements = 0; break; case FW_FIRE_FLASH: mbox->cmd = FW_FIRE_FLASH; mbox->channel = data[1] | 0x80; /* Origin */ set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE); mbox->numsgelements = 0; break; case DCMD_FC_CMD: *(mboxdata + 0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD */ *(mboxdata + 2) = data[1]; /*sub command */ switch (data[1]) { case DCMD_FC_READ_NVRAM_CONFIG: case DCMD_FC_READ_NVRAM_CONFIG_64: /* number of elements in SG list */ *(mboxdata + 3) = mbox->numsgelements; if (megaCfg->flag & BOARD_64BIT) *(mboxdata + 2) = DCMD_FC_READ_NVRAM_CONFIG_64; break; case DCMD_WRITE_CONFIG: case DCMD_WRITE_CONFIG_64: if (megaCfg->flag & BOARD_64BIT) *(mboxdata + 2) = DCMD_WRITE_CONFIG_64; set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE); mbox->numsgelements = 0; break; case DCMD_GET_DISK_CONFIG: case DCMD_GET_DISK_CONFIG_64: if (megaCfg->flag & BOARD_64BIT) *(mboxdata + 2) = DCMD_GET_DISK_CONFIG_64; *(mboxdata + 3) = data[2]; /*number of elements in SG list */ /*nr of elements in SG list */ *(mboxdata + 4) = mbox->numsgelements; break; case DCMD_DELETE_LOGDRV: case DCMD_DELETE_DRIVEGROUP: case NC_SUBOP_ENQUIRY3: *(mboxdata + 3) = data[2]; set_mbox_xfer_addr (megaCfg, pScb, mbox,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -