#151d
#幅優先探索、二次元入力、番兵、門番、行列
from collections import deque

H,W = map(int, input().split())

edge = [["#" for _ in range(W+2)]]
center = [["#"] + list(input()) + ["#"] for i in range(H)]
c_array = edge + center + edge

caluclated_edge = [[1 for _ in range(W+2)]]
caluclated_center = [[1] + [0 for _ in range(W)] + [1] for i in range(H)]
is_caluclated = caluclated_edge + caluclated_center + caluclated_edge

def visited_print():
    print("$$$$$$$$$$$$$$$$$$$$$$")
    for i in range(0,H+2):
        print(is_visited[i][0:W+2])

def map_print():
    print("######################")
    for i in range(0,H+2):
        print(distance_from_start[i][1:W+1])

def get_farthest_dead_end(sy,sx): #function 幅優先探索(v)
    distance_from_start = [["?"] * (W+2) for i in range(H+2)] #startからの距離

    iv_edge = [[1 for _ in range(W+2)]]
    iv_center = [[1] + [0 for _ in range(W)] + [1] for i in range(H)]
    is_visited = iv_edge + iv_center + iv_edge

    search_target_deque = deque() #    Q ← 空のキュー
    is_visited[sy][sx] = 1 #    v に訪問済みの印を付ける
    search_target_deque.append((sy,sx)) #    v を Q に追加
    distance_from_start[sy][sx] = 0

    farthest_dead_end_y = sy
    farthest_dead_end_x = sx
    farthest_dead_end_distance = 0

    while len(search_target_deque) != 0: #    while Q が空ではない do
        node = search_target_deque.popleft() #        v ← Q から取り出す
        #        v を処理する
        node_y = node[0]
        node_x = node[1]

        near_nodes = [(node[0]+1,node[1]),(node[0],node[1]+1),(node[0]-1,node[1]),(node[0],node[1]-1)]
        maybe_dead_end_flag = True

        for near_node in near_nodes: #        for each v に接続している頂点 i do
            near_node_y = near_node[0]
            near_node_x = near_node[1]

            if is_visited[near_node_y][near_node_x] == 0: #            if i が未訪問 then
                is_visited[near_node_y][near_node_x] = 1 #                i に訪問済みの印を付ける
                if c_array[near_node_y][near_node_x] == ".":
                    search_target_deque.append(near_node) #                i を Q に追加
                    distance_from_start[near_node_y][near_node_x] = distance_from_start[node_y][node_x] + 1
                    maybe_dead_end_flag = False

        #行き止まり判定
        if maybe_dead_end_flag == True:
            now_distance = distance_from_start[node_y][node_x]
            for near_node in near_nodes:
                #周囲に未訪問マスがある or 自分より通りマスがある ならば行き止まりでない 
                near_node_y = near_node[0]
                near_node_x = near_node[1]

                if (distance_from_start[near_node_y][near_node_x] != "?" and  now_distance < distance_from_start[near_node_y][near_node_x]):
                    break
                if is_visited[near_node_y][near_node_x]==0:
                    break
            else:
                if farthest_dead_end_distance < distance_from_start[node_y][node_x]:
                    farthest_dead_end_distance = distance_from_start[node_y][node_x]
                    farthest_dead_end_y = node_y
                    farthest_dead_end_x = node_x

    return farthest_dead_end_y,farthest_dead_end_x


def get_ans(sy,sx): #function 幅優先探索(v)
    distance_from_start = [["?"] * (W+2) for i in range(H+2)] #startからの距離

    iv_edge = [[1 for _ in range(W+2)]]
    iv_center = [[1] + [0 for _ in range(W)] + [1] for i in range(H)]
    is_visited = iv_edge + iv_center + iv_edge

    search_target_deque = deque() #    Q ← 空のキュー
    is_visited[sy][sx] = 1 #    v に訪問済みの印を付ける
    is_caluclated[sy][sx] = 1

    search_target_deque.append((sy,sx)) #    v を Q に追加
    distance_from_start[sy][sx] = 0

    ans = 0

    while len(search_target_deque) != 0: #    while Q が空ではない do
        node = search_target_deque.popleft() #        v ← Q から取り出す
        #        v を処理する
        node_y = node[0]
        node_x = node[1]
                
        near_nodes = [(node[0]+1,node[1]),(node[0],node[1]+1),(node[0]-1,node[1]),(node[0],node[1]-1)]
        maybe_dead_end_flag = True

        for near_node in near_nodes: #        for each v に接続している頂点 i do
            near_node_y = near_node[0]
            near_node_x = near_node[1]

            if is_visited[near_node_y][near_node_x] == 0: #            if i が未訪問 then
                is_visited[near_node_y][near_node_x] = 1 #                i に訪問済みの印を付ける
                is_caluclated[near_node_y][near_node_x] = 1
                if c_array[near_node_y][near_node_x] == ".":
                    search_target_deque.append(near_node) #                i を Q に追加
                    distance_from_start[near_node_y][near_node_x] = distance_from_start[node_y][node_x] + 1
                    maybe_dead_end_flag = False

        #行き止まり判定
        if maybe_dead_end_flag == True:
            now_distance = distance_from_start[node_y][node_x]
            for near_node in near_nodes:
                #周囲に未訪問マスがある or 自分より通りマスがある ならば行き止まりでない 
                near_node_y = near_node[0]
                near_node_x = near_node[1]

                if (distance_from_start[near_node_y][near_node_x] != "?" and  now_distance < distance_from_start[near_node_y][near_node_x]):
                    break
                if is_visited[near_node_y][near_node_x]==0:
                    break
            else:
                if ans < distance_from_start[node_y][node_x]:
                    ans = distance_from_start[node_y][node_x]

    return ans

#行き止まりを求めて、一番遠いところから広げてみる。
ans = 1

#仮スタートを決める
break_flag = False
for i in range(1,H+1):
    for j in range(1,W+1):
        if c_array[i][j]=="." and is_caluclated[i][j]==0:
            sy = i
            sx = j
            sy,sx = get_farthest_dead_end(sy,sx)
            temp_ans = get_ans(sy,sx)
            if ans < temp_ans:
                ans = temp_ans

print(ans)