3. SSD의 깊숙한 구조! jasmine open SSD technical manual

위 내용은 The Jasmine OpenSSD Platform 의 FTL Developer's Guide를 정리하고 참고하였다. jasmine은 내가 이번 방학동안 대학 연구실에서 공부하고 프로그래밍한 개발자용 SSD로, factory모드가 있어, 내가 직접 코드를 쓰고 실행할 수 있다. 해당 openSSD는 http://www.openssd-project.org/ 에서 찾아볼 수 있다.

1. SSD 의 전체 구조


그림 1. SSD 구조 <출처 : The Jasmine OpenSSD Platform>

그림1에 있는 것이 바로 SSD의 구조이다. 복잡해보이고 여러개가 나부라져있는데, 여기서 핵심을 집고 넘어간다. SSD는 말했다시피, 기계적으로 작동하는 멍청한 하드디스크와는 달리, 전기로 움직이며, 자체 내에 cpu, dram이 존재하여 폰노이만 아키텍쳐를 구사하는 마치 작은 컴퓨터같은 놈이다.

1. Barefoot SSD controller :  이놈이 바로 SSD의 cpu역할을 한다. host의 명령, 시스템 전체, flash 의 데이터를 전체적으로 관리한다.

2. moblie SDRAM : 이 놈은 SSD의 ram 역할을 수행한다. mapping table이 바로 이곳에 저장된다. 또 ftl등의 code역시 이곳에 저장된다. 아주 중요하므로 자세한 것은 밑에서 다시 다룬다.

3. Nand flash : 실제 데이터가 저장되는 장소이다. jasmine기준으로 볼때 4개의 channel로 구성되어 있다. 각 channel 은 8개의 bank로 구성되어 있으며, 각 bank에 데이터들이 저장된다. 이놈 역시 밑에서 깊숙히 다룬다.


2. Nand flash 구조

Nand flash는 높은 bandwidth(대역폭 : 초당 얼마나 보내는지)을 제공하기 위하여 다중 channel 및 다중 way 기반으로 설계되었다.


그림 2. flash 구조 <출처 : The Jasmine OpenSSD Platform>

open SSD는 병렬적, 독립적으로 움직이는 4개의 channel로 이루어 진다. 각 channel 은 8개의 bank 로 구성되어있으며, 각 bank는 2개의 Nand flash 칩(high, low)으로 구성된다. 이는 그림2를 통해 확인할 수 있다. 여기서 내부구조가 어떤부분이 병렬적으로 구성되어 있는지 주목해보자. 병렬적으로 구성되어있다는 것은 interleaving IO, 즉 동시에 i/o가 가능함을 의미한다.

1. 각 channel은 병렬적으로 구성되어 있다.

2. channel 내 8개의 bank는 병렬적으로 구성되어 있지 않다.
->channel 내에는 2개의 bank에 대하여 R/B 출력핀을 가지고 있다. 다시 말해, 4개의 R/B출력핀을 가지므로 최대 4개까지 interleaving IO가 가능하다. 좀더 자세히 설명하자면, A0 A4 / A1 A5 / A2 A6 / A3 A7 bank는 각 하나의 R/B출력핀으로 구성되어 있다. 즉 A0,A4는 동시에 입출력이 불가하지만, A0, A5, A2, A7 bank는 동시에 입출력이 가능하다.

3. 각 bank 내 2개의 플래시칩은 병렬적으로 구성되어 있다.
-> 따라서 bank는 2개의 플래시칩을 번갈아가면서 데이터를 동시에 저장한다. 그림3을 보자.


그림 3. bank 내 write 방식 <출처 : The Jasmine OpenSSD Platform>

그림3과 같이 data를 write할 때에는 해당 bank의 low 칩과 high칩에 번갈아가며 write가 된다. 다시 말해 두개의 칩은 하나의 가상칩으로 간주된다. 또, 동시에 저장되므로 이 방식은 write시간을 2배 단축시킬 것이다. 이 역할은 당연히 barefoot controller가 수행한다.

-가상 페이지 vs 물리 페이지
우선, 그림3 에서 살펴봤듯이, 2개의 물리페이지는 1개의 가상페이지로써 간주된다. 대체적인 플래시 메모리는 2plane-mode를 지원하는데, 이는 두페이지를 하나의 가상적인 페이지로 묶어서 읽거나 쓰는 것이다. 즉 2 plane-mode를 지원할때는 페이지의 수가 절반으로 줄어들고, 페이지의 크기가 두배로 늘어나는 효과가 발생한다. 이 모드에서는 결국 4개의 물리페이지가 1개의 가상페이지로 간주된다.


3. SDRAM

그림 4. 출처 : The Jasmine OpenSSD Platform



그림 5. 출처 : The Jasmine OpenSSD Platform





SDRAM 은 폰 노이만 아키텍쳐의 memory역할로 바라보면 된다. 그림 4,5와 같은 구조로 이루어져 있으며, mapping table, 데이터를 전달하기 위한 각종 buffer, 그리고 부팅시 작동하는 meta data등이 여기 있다.


4. SSD의 메인 펌웨어 구조

open SSD의 경우, 메인 펌웨어는 크게 3가지로 나눌 수 있다. HIL(Host Interface Layer)은 host단에서의 데이터 I/O 요청을 담당한다. 두번째로 FTL(Flash Translation Layer)은 host와 flash사이를 연결해주며, cost 를 최소화(erase 연산을 최소화)시켜줄 수 있는 위치의 flash주소를 찾아준다. 세번째로 FIL(Flash Interface Layer) 은 flash 내 실제 I/O 를 담당한다. 이는 LLD(Low-level device driver) 에 의해 수행된다.

그림 6. 출처  <The Jasmine OpenSSD Platform>

1. HIL(Host Interface Layer)
HIL에서는 호스트의 I/O명령을 담당한다. barefoot controller 내에 있는 SATA controller에 의해 일어난다.

그림 7. 출처  <The Jasmine OpenSSD Platform>


1. SATA NCQ : HOST로 부터 I/O 명령을 처음으로 받아들이는 SATA 명령 프로토콜이다. FIFO 방식으로 작동하며 이후 HOST명령 protocol 은 SATA 이벤트큐로 이동하게 된다.

2. SATA event queue : HOST 관점에서 SATA 데이터 전송이 완료된 아이들을 보관하는 공간이다. 이 데이터는 아직 실제 I/O가 수행되지 않았으며, FTL이 수행을 위해 issue하면 제거된다.


그림 8. 출처  <The Jasmine OpenSSD Platform>
-SATA Read buffer 은 SATA Write buffer 과 같이 이벤트 큐의 요청에 대한 실제 사용자 데이터를 버퍼링하는 과정에서 사용된다. buffer 는 원형 버퍼(circular buffer)의 형태로 작동한다. 보통 SATA Read buffer 은 1MB, SATA Write buffer은 수십 MB 의 크기를 가진다.

3. SATA Read buffer : 이벤트 큐의 read요청을 수행하기 위한 버퍼이다. 우선 nand flash로 부터 데이터를 읽어와 ftl_read_ptr이 가리키는 주소에 해당 내용을 로드한다. 이후 sata_read_ptr은 buffer에 저장된 데이터를 host에게 전달한다. 이 과정에서 bandwidth의 차이로 인해 sata_read_ptr이 ftl_read_ptr을 추월할 수 있는데, 이를 막기 위해 사이에 bm_read_ptr을 둔다.

4. SATA Write buffer : 이벤트 큐의 write요청을 수행하기 위한 버퍼이다. 우선 사용자의 데이터를 sata_write_buffer에 로드한다. 이후 ftl_write_ptr에서는 해당 데이터를 nand flash에 보내 write를 수행하도록 한다. 이 과정에서 역시 느린 flash write속도로 인해 sata_write_ptr이 ftl_write_ptr을 추월할 수 있는데 이를 막기 위해 사이에 bm_write_ptr을 둔다.


2. FIL(Flash Interface Layer)

FIL에서는 flash내 실제 read/write를 담당한다. 이 명령은 LLD(Low-level device driver)에서 수행되며, LLD란 플래시 명령을 FCP에 전달하고, 이를 WR에 전달하는 인터페이스이다.

그림 9. 출처  <The Jasmine OpenSSD Platform>

우선 flash에 내릴 I/O 명령을 FCP에 저장한다. FTL이 이를 isssue 시키면 해당 명령은 WR로 넘어간다. WR은 깊이가 1인 큐로, 해당 bank가 busy하면 대기하다가, idle할 때 명령을 실행한다. 실행한 명령은 각 bank마다 있는 BSP에 저장되므로, 디버깅할때 BSP에 저장된 명령 내역을 볼 수 있도록 해준다.

1. FCP : Flash에 I/O명령을 수행하기 위해서는 우선 FCP 를 설정해야 한다. FCP 에는 bank갯수, flash 명령, 버퍼주소, row,column등이 존재하며, 이를 설정하고 issue시키면 WR으로 넘어가게 된다.

2. WR : 해당 명령이 flash에 전달되기 전에 잠시 대기하는 장소이며, 해당 bank가 idle일때 명령을 전달한다.

3. BSP : 각 bank마다 가지고 있으며, WR이 보낸 정보를 그대로 저장하므로, 이는 나중에 디버깅하기에 용이하다.


3. FTL(Flash Translation Layer)

FTL 은 HOST 의 명령과 실제 flash의 수행을 cost effective하도록 이어주는 역할을 한다. 구체적으로 말하자면, HOST의 요청 주소(logical address)와 실제 Flash의 주소(physical address)를 mapping시켜준다.

그림 10. 출처  <The Jasmine OpenSSD Platform>


1. Read operation : read 수행시 이루어지는 연산은 그림9와 같다. FTL은 flash로 부터 page 단위로 data를 읽어와 SATA Read buffer에 로드한다. 그러나 HOST는 page단위가 아닌 sector단위(1page=128sector)로 데이터를 요청하므로, 해당되는 부분만을 host에 전달한다.


그림 11. 출처  <The Jasmine OpenSSD Platform>

2. Write operation : write연산시 수행되는 연산은 그림10과 같다. HOST의 데이터를 SATA write buffer에 로드하고, 비어있는 부분은 nand flash의 기존 데이터를 읽어서 로드한다. 이렇게하면 1page가 완벽히 write되는데, 이를 flash에 전달하여 새로운 페이지에 저장하게 된다.


5. 추가! copy buffer의 동작!
 플래시 메모리 내에서 데이터를 복사해야 할 경우 copy buffer을 이용한다.  메인프레임 내 copy buffer이 어떻게 동작하는지 알아보자.

그림 12. 출처  <The Jasmine OpenSSD Platform>

그런데 여기서 특이한 점은 nand flash는 primitive operation으로 copy를 자체적으로 처리할 수 있다는 점이다. 그러면 대체 왜 자체적으로 처리하지 않고 dram에 복사해서 복잡한 연산을 수행할까? ECC검증과정이 필요하기 때문이다. ECC 검증이란 데이터의 신뢰성을 검증하기 위한 것으로, 128byte의 데이터당 4byte의 패리티정보를 붙여서, 이를 통해 data consistency를 확인하는 것이다.

우선 nand flash의 데이터를 flash 내 register에 저장하고, 이를 DRAM controller로 로드한다. 이후 ECC 를 검증하기 위해 DRAM 의 copy buffer공간에 데이터를 복사하고, DRAM controller내에 데이터와 ECC검증과정을 수행한다. ECC 정정이 필요할 경우 3, 4의 과정을 거쳐서 copy를 수행하며, 필요하지 않을 경우에는 이 과정을 거치지 않고 nand 의 page register에 저장된 데이터를 바로 자체적으로 카피한다.

끄읕~!














댓글

댓글 쓰기

가장 많이 본 글